Commit 2006a11ce142
tarball7 files changed+1128-30
@@ -0,0 +1,851 @@
1
+# This file is automatically @generated by Cargo.2
+# It is not intended for manual editing.3
+version = 44
+5
+[[package]]6
+name = "aho-corasick"7
+version = "1.1.5"8
+source = "registry+https://github.com/rust-lang/crates.io-index"9
+checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"10
+dependencies = [11
+ "memchr",12
+]13
+14
+[[package]]15
+name = "as_variant"16
+version = "1.3.0"17
+source = "registry+https://github.com/rust-lang/crates.io-index"18
+checksum = "9dbc3a507a82b17ba0d98f6ce8fd6954ea0c8152e98009d36a40d8dcc8ce078a"19
+20
+[[package]]21
+name = "base64"22
+version = "0.22.1"23
+source = "registry+https://github.com/rust-lang/crates.io-index"24
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"25
+26
+[[package]]27
+name = "bumpalo"28
+version = "3.20.3"29
+source = "registry+https://github.com/rust-lang/crates.io-index"30
+checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"31
+32
+[[package]]33
+name = "bytes"34
+version = "1.12.1"35
+source = "registry+https://github.com/rust-lang/crates.io-index"36
+checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"37
+38
+[[package]]39
+name = "cfg-if"40
+version = "1.0.5"41
+source = "registry+https://github.com/rust-lang/crates.io-index"42
+checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"43
+44
+[[package]]45
+name = "deranged"46
+version = "0.5.9"47
+source = "registry+https://github.com/rust-lang/crates.io-index"48
+checksum = "9e9de72ce2ad1f90dc62fa25f0f430ef85eb4b0d8fa0be4f30373bc40a21d28e"49
+50
+[[package]]51
+name = "displaydoc"52
+version = "0.2.7"53
+source = "registry+https://github.com/rust-lang/crates.io-index"54
+checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8"55
+dependencies = [56
+ "proc-macro2",57
+ "quote",58
+ "syn 3.0.9",59
+]60
+61
+[[package]]62
+name = "equivalent"63
+version = "1.0.3"64
+source = "registry+https://github.com/rust-lang/crates.io-index"65
+checksum = "00d174d5400e5e8fd687ad1049e2f578285fa914201b1af7e8b112a4546bd826"66
+67
+[[package]]68
+name = "form_urlencoded"69
+version = "1.2.2"70
+source = "registry+https://github.com/rust-lang/crates.io-index"71
+checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"72
+dependencies = [73
+ "percent-encoding",74
+]75
+76
+[[package]]77
+name = "futures-core"78
+version = "0.3.34"79
+source = "registry+https://github.com/rust-lang/crates.io-index"80
+checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e"81
+82
+[[package]]83
+name = "futures-task"84
+version = "0.3.34"85
+source = "registry+https://github.com/rust-lang/crates.io-index"86
+checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd"87
+88
+[[package]]89
+name = "futures-util"90
+version = "0.3.34"91
+source = "registry+https://github.com/rust-lang/crates.io-index"92
+checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc"93
+dependencies = [94
+ "futures-core",95
+ "futures-task",96
+ "pin-project-lite",97
+ "slab",98
+]99
+100
+[[package]]101
+name = "hashbrown"102
+version = "0.17.1"103
+source = "registry+https://github.com/rust-lang/crates.io-index"104
+checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"105
+106
+[[package]]107
+name = "icu_collections"108
+version = "2.4.0"109
+source = "registry+https://github.com/rust-lang/crates.io-index"110
+checksum = "fe090a42a0d3140fed8c63263ed1fecc02422cb2f4bfe55cd8de2de1b8e105dd"111
+dependencies = [112
+ "displaydoc",113
+ "potential_utf",114
+ "utf8_iter",115
+ "yoke",116
+ "zerofrom",117
+ "zerovec",118
+]119
+120
+[[package]]121
+name = "icu_locale_core"122
+version = "2.4.0"123
+source = "registry+https://github.com/rust-lang/crates.io-index"124
+checksum = "25d29b57c17c6528d0dc4c2141cfa2d08200465acb537a3909c8b9b8a4a984c0"125
+dependencies = [126
+ "displaydoc",127
+ "litemap",128
+ "tinystr",129
+ "writeable",130
+ "zerovec",131
+]132
+133
+[[package]]134
+name = "icu_normalizer"135
+version = "2.4.0"136
+source = "registry+https://github.com/rust-lang/crates.io-index"137
+checksum = "404a3b8c486f205c87fe7f23ab6894d84a4ad76d6e4671ae1981ba7def87c599"138
+dependencies = [139
+ "icu_collections",140
+ "icu_normalizer_data",141
+ "icu_properties",142
+ "icu_provider",143
+ "smallvec",144
+ "zerovec",145
+]146
+147
+[[package]]148
+name = "icu_normalizer_data"149
+version = "2.4.0"150
+source = "registry+https://github.com/rust-lang/crates.io-index"151
+checksum = "20f0088bfb7441f7a37fa0c9e20cb1e9cba1cac6b9ce8cd2a6dc44294f8e8cbc"152
+153
+[[package]]154
+name = "icu_properties"155
+version = "2.4.0"156
+source = "registry+https://github.com/rust-lang/crates.io-index"157
+checksum = "2ea83d991c56158f7cf898bf86436c1dfe7c07ee82fe88951f2695c9f37a379f"158
+dependencies = [159
+ "displaydoc",160
+ "icu_collections",161
+ "icu_locale_core",162
+ "icu_properties_data",163
+ "icu_provider",164
+ "zerotrie",165
+ "zerovec",166
+]167
+168
+[[package]]169
+name = "icu_properties_data"170
+version = "2.4.0"171
+source = "registry+https://github.com/rust-lang/crates.io-index"172
+checksum = "b98f29af82d02b163fe50161388350e743bb3107cc8e8c2f7314cb505faddfcf"173
+174
+[[package]]175
+name = "icu_provider"176
+version = "2.4.0"177
+source = "registry+https://github.com/rust-lang/crates.io-index"178
+checksum = "413099315636c588ee8f011190b329b971a09a8fae9d157e01dcae8379468514"179
+dependencies = [180
+ "displaydoc",181
+ "icu_locale_core",182
+ "writeable",183
+ "yoke",184
+ "zerofrom",185
+ "zerotrie",186
+ "zerovec",187
+]188
+189
+[[package]]190
+name = "idna"191
+version = "1.1.0"192
+source = "registry+https://github.com/rust-lang/crates.io-index"193
+checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"194
+dependencies = [195
+ "idna_adapter",196
+ "smallvec",197
+ "utf8_iter",198
+]199
+200
+[[package]]201
+name = "idna_adapter"202
+version = "1.2.2"203
+source = "registry+https://github.com/rust-lang/crates.io-index"204
+checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714"205
+dependencies = [206
+ "icu_normalizer",207
+ "icu_properties",208
+]209
+210
+[[package]]211
+name = "indexmap"212
+version = "2.14.2"213
+source = "registry+https://github.com/rust-lang/crates.io-index"214
+checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855"215
+dependencies = [216
+ "equivalent",217
+ "hashbrown",218
+ "serde",219
+ "serde_core",220
+]221
+222
+[[package]]223
+name = "itoa"224
+version = "1.0.18"225
+source = "registry+https://github.com/rust-lang/crates.io-index"226
+checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"227
+228
+[[package]]229
+name = "js-sys"230
+version = "0.3.106"231
+source = "registry+https://github.com/rust-lang/crates.io-index"232
+checksum = "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5"233
+dependencies = [234
+ "cfg-if",235
+ "futures-util",236
+ "wasm-bindgen",237
+]238
+239
+[[package]]240
+name = "js_int"241
+version = "0.2.2"242
+source = "registry+https://github.com/rust-lang/crates.io-index"243
+checksum = "d937f95470b270ce8b8950207715d71aa8e153c0d44c6684d59397ed4949160a"244
+dependencies = [245
+ "serde",246
+]247
+248
+[[package]]249
+name = "litemap"250
+version = "0.8.3"251
+source = "registry+https://github.com/rust-lang/crates.io-index"252
+checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae"253
+254
+[[package]]255
+name = "macltok-push-gateway"256
+version = "0.1.0"257
+dependencies = [258
+ "ruma-common",259
+ "serde",260
+ "serde_json",261
+]262
+263
+[[package]]264
+name = "memchr"265
+version = "2.8.3"266
+source = "registry+https://github.com/rust-lang/crates.io-index"267
+checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"268
+269
+[[package]]270
+name = "num-conv"271
+version = "0.2.2"272
+source = "registry+https://github.com/rust-lang/crates.io-index"273
+checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"274
+275
+[[package]]276
+name = "once_cell"277
+version = "1.21.4"278
+source = "registry+https://github.com/rust-lang/crates.io-index"279
+checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"280
+281
+[[package]]282
+name = "percent-encoding"283
+version = "2.3.2"284
+source = "registry+https://github.com/rust-lang/crates.io-index"285
+checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"286
+287
+[[package]]288
+name = "pin-project-lite"289
+version = "0.2.17"290
+source = "registry+https://github.com/rust-lang/crates.io-index"291
+checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"292
+293
+[[package]]294
+name = "potential_utf"295
+version = "0.1.6"296
+source = "registry+https://github.com/rust-lang/crates.io-index"297
+checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661"298
+dependencies = [299
+ "zerovec",300
+]301
+302
+[[package]]303
+name = "powerfmt"304
+version = "0.2.1"305
+source = "registry+https://github.com/rust-lang/crates.io-index"306
+checksum = "4a6394b9e965e73d0a289ee54f589087e2c676aedf60885baf52c76b771e4958"307
+308
+[[package]]309
+name = "proc-macro-crate"310
+version = "3.5.0"311
+source = "registry+https://github.com/rust-lang/crates.io-index"312
+checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"313
+dependencies = [314
+ "toml_edit",315
+]316
+317
+[[package]]318
+name = "proc-macro2"319
+version = "1.0.107"320
+source = "registry+https://github.com/rust-lang/crates.io-index"321
+checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"322
+dependencies = [323
+ "unicode-ident",324
+]325
+326
+[[package]]327
+name = "quote"328
+version = "1.0.47"329
+source = "registry+https://github.com/rust-lang/crates.io-index"330
+checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"331
+dependencies = [332
+ "proc-macro2",333
+]334
+335
+[[package]]336
+name = "regex"337
+version = "1.13.1"338
+source = "registry+https://github.com/rust-lang/crates.io-index"339
+checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"340
+dependencies = [341
+ "aho-corasick",342
+ "memchr",343
+ "regex-automata",344
+ "regex-syntax",345
+]346
+347
+[[package]]348
+name = "regex-automata"349
+version = "0.4.18"350
+source = "registry+https://github.com/rust-lang/crates.io-index"351
+checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"352
+dependencies = [353
+ "aho-corasick",354
+ "memchr",355
+ "regex-syntax",356
+]357
+358
+[[package]]359
+name = "regex-syntax"360
+version = "0.8.11"361
+source = "registry+https://github.com/rust-lang/crates.io-index"362
+checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"363
+364
+[[package]]365
+name = "ruma-common"366
+version = "0.19.0"367
+source = "registry+https://github.com/rust-lang/crates.io-index"368
+checksum = "2c3b4f00112791b490acce57df1ce3eb3f88899b045bebcff8a29f75369640cc"369
+dependencies = [370
+ "as_variant",371
+ "base64",372
+ "bytes",373
+ "form_urlencoded",374
+ "indexmap",375
+ "js_int",376
+ "percent-encoding",377
+ "regex",378
+ "ruma-identifiers-validation",379
+ "ruma-macros",380
+ "serde",381
+ "serde_html_form",382
+ "serde_json",383
+ "thiserror",384
+ "time",385
+ "tracing",386
+ "url",387
+ "web-time",388
+ "wildmatch",389
+ "zeroize",390
+]391
+392
+[[package]]393
+name = "ruma-identifiers-validation"394
+version = "0.12.1"395
+source = "registry+https://github.com/rust-lang/crates.io-index"396
+checksum = "9d6cff00317675f487c4e7ccfb18875a14c5a14867b51d13f2a826053f03c432"397
+dependencies = [398
+ "js_int",399
+ "thiserror",400
+]401
+402
+[[package]]403
+name = "ruma-macros"404
+version = "0.19.0"405
+source = "registry+https://github.com/rust-lang/crates.io-index"406
+checksum = "c8cfb39eaa9b9fd389126ff941e060b496add5cbbfef559d80c46e571dda459c"407
+dependencies = [408
+ "as_variant",409
+ "cfg-if",410
+ "proc-macro-crate",411
+ "proc-macro2",412
+ "quote",413
+ "ruma-identifiers-validation",414
+ "serde",415
+ "syn 2.0.119",416
+ "toml",417
+]418
+419
+[[package]]420
+name = "rustversion"421
+version = "1.0.23"422
+source = "registry+https://github.com/rust-lang/crates.io-index"423
+checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"424
+425
+[[package]]426
+name = "serde"427
+version = "1.0.229"428
+source = "registry+https://github.com/rust-lang/crates.io-index"429
+checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"430
+dependencies = [431
+ "serde_core",432
+ "serde_derive",433
+]434
+435
+[[package]]436
+name = "serde_core"437
+version = "1.0.229"438
+source = "registry+https://github.com/rust-lang/crates.io-index"439
+checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"440
+dependencies = [441
+ "serde_derive",442
+]443
+444
+[[package]]445
+name = "serde_derive"446
+version = "1.0.229"447
+source = "registry+https://github.com/rust-lang/crates.io-index"448
+checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"449
+dependencies = [450
+ "proc-macro2",451
+ "quote",452
+ "syn 3.0.9",453
+]454
+455
+[[package]]456
+name = "serde_html_form"457
+version = "0.4.1"458
+source = "registry+https://github.com/rust-lang/crates.io-index"459
+checksum = "8f0346d7a342ab90f405cfc08f25d15075f944f42fcabbc5eac923829fa6d228"460
+dependencies = [461
+ "form_urlencoded",462
+ "indexmap",463
+ "itoa",464
+ "serde_core",465
+ "zmij",466
+]467
+468
+[[package]]469
+name = "serde_json"470
+version = "1.0.154"471
+source = "registry+https://github.com/rust-lang/crates.io-index"472
+checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6"473
+dependencies = [474
+ "itoa",475
+ "memchr",476
+ "serde",477
+ "serde_core",478
+ "zmij",479
+]480
+481
+[[package]]482
+name = "serde_spanned"483
+version = "1.1.2"484
+source = "registry+https://github.com/rust-lang/crates.io-index"485
+checksum = "4e7523beb55eece201a2356bee0bbca0d1ab466c14c07703b2e0ee6d42cb0c2c"486
+dependencies = [487
+ "serde_core",488
+]489
+490
+[[package]]491
+name = "slab"492
+version = "0.4.12"493
+source = "registry+https://github.com/rust-lang/crates.io-index"494
+checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"495
+496
+[[package]]497
+name = "smallvec"498
+version = "1.16.4"499
+source = "registry+https://github.com/rust-lang/crates.io-index"500
+checksum = "d0d5d4b1981b8bbbb7aed204cae5726d683d5d6ac7e74ec54122ea28f315e7c8"501
+502
+[[package]]503
+name = "stable_deref_trait"504
+version = "1.2.1"505
+source = "registry+https://github.com/rust-lang/crates.io-index"506
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"507
+508
+[[package]]509
+name = "syn"510
+version = "2.0.119"511
+source = "registry+https://github.com/rust-lang/crates.io-index"512
+checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"513
+dependencies = [514
+ "proc-macro2",515
+ "quote",516
+ "unicode-ident",517
+]518
+519
+[[package]]520
+name = "syn"521
+version = "3.0.9"522
+source = "registry+https://github.com/rust-lang/crates.io-index"523
+checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b"524
+dependencies = [525
+ "proc-macro2",526
+ "quote",527
+ "unicode-ident",528
+]529
+530
+[[package]]531
+name = "synstructure"532
+version = "0.14.0"533
+source = "registry+https://github.com/rust-lang/crates.io-index"534
+checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02"535
+dependencies = [536
+ "proc-macro2",537
+ "quote",538
+ "syn 3.0.9",539
+]540
+541
+[[package]]542
+name = "thiserror"543
+version = "2.0.21"544
+source = "registry+https://github.com/rust-lang/crates.io-index"545
+checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e"546
+dependencies = [547
+ "thiserror-impl",548
+]549
+550
+[[package]]551
+name = "thiserror-impl"552
+version = "2.0.21"553
+source = "registry+https://github.com/rust-lang/crates.io-index"554
+checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524"555
+dependencies = [556
+ "proc-macro2",557
+ "quote",558
+ "syn 3.0.9",559
+]560
+561
+[[package]]562
+name = "time"563
+version = "0.3.55"564
+source = "registry+https://github.com/rust-lang/crates.io-index"565
+checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134"566
+dependencies = [567
+ "deranged",568
+ "num-conv",569
+ "powerfmt",570
+ "serde_core",571
+ "time-core",572
+]573
+574
+[[package]]575
+name = "time-core"576
+version = "0.1.9"577
+source = "registry+https://github.com/rust-lang/crates.io-index"578
+checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"579
+580
+[[package]]581
+name = "tinystr"582
+version = "0.8.5"583
+source = "registry+https://github.com/rust-lang/crates.io-index"584
+checksum = "abc840c238154d58f9e86b2792261edfde565a17696e1cda1a449de27979801a"585
+dependencies = [586
+ "displaydoc",587
+ "zerovec",588
+]589
+590
+[[package]]591
+name = "toml"592
+version = "1.1.8+spec-1.1.0"593
+source = "registry+https://github.com/rust-lang/crates.io-index"594
+checksum = "20489e00e4d8741d6be680764cc12e270655e375a20d1011e844a9c3379e678d"595
+dependencies = [596
+ "serde_core",597
+ "serde_spanned",598
+ "toml_datetime",599
+ "toml_parser",600
+ "winnow",601
+]602
+603
+[[package]]604
+name = "toml_datetime"605
+version = "1.1.2+spec-1.1.0"606
+source = "registry+https://github.com/rust-lang/crates.io-index"607
+checksum = "2b86d767906c6c42421dcba507eb9d203e779497710a47782a224bb871653053"608
+dependencies = [609
+ "serde_core",610
+]611
+612
+[[package]]613
+name = "toml_edit"614
+version = "0.25.17+spec-1.1.0"615
+source = "registry+https://github.com/rust-lang/crates.io-index"616
+checksum = "e3641d5bbb5349a79e1020a242d251efbc546ad8048d133958323ce9c40a9c9c"617
+dependencies = [618
+ "indexmap",619
+ "toml_datetime",620
+ "toml_parser",621
+ "winnow",622
+]623
+624
+[[package]]625
+name = "toml_parser"626
+version = "1.1.5+spec-1.1.0"627
+source = "registry+https://github.com/rust-lang/crates.io-index"628
+checksum = "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c"629
+dependencies = [630
+ "winnow",631
+]632
+633
+[[package]]634
+name = "tracing"635
+version = "0.1.44"636
+source = "registry+https://github.com/rust-lang/crates.io-index"637
+checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"638
+dependencies = [639
+ "pin-project-lite",640
+ "tracing-attributes",641
+ "tracing-core",642
+]643
+644
+[[package]]645
+name = "tracing-attributes"646
+version = "0.1.31"647
+source = "registry+https://github.com/rust-lang/crates.io-index"648
+checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"649
+dependencies = [650
+ "proc-macro2",651
+ "quote",652
+ "syn 2.0.119",653
+]654
+655
+[[package]]656
+name = "tracing-core"657
+version = "0.1.36"658
+source = "registry+https://github.com/rust-lang/crates.io-index"659
+checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"660
+dependencies = [661
+ "once_cell",662
+]663
+664
+[[package]]665
+name = "unicode-ident"666
+version = "1.0.27"667
+source = "registry+https://github.com/rust-lang/crates.io-index"668
+checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"669
+670
+[[package]]671
+name = "url"672
+version = "2.5.8"673
+source = "registry+https://github.com/rust-lang/crates.io-index"674
+checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"675
+dependencies = [676
+ "form_urlencoded",677
+ "idna",678
+ "percent-encoding",679
+ "serde",680
+]681
+682
+[[package]]683
+name = "utf8_iter"684
+version = "1.0.4"685
+source = "registry+https://github.com/rust-lang/crates.io-index"686
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"687
+688
+[[package]]689
+name = "wasm-bindgen"690
+version = "0.2.129"691
+source = "registry+https://github.com/rust-lang/crates.io-index"692
+checksum = "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409"693
+dependencies = [694
+ "cfg-if",695
+ "once_cell",696
+ "rustversion",697
+ "wasm-bindgen-macro",698
+ "wasm-bindgen-shared",699
+]700
+701
+[[package]]702
+name = "wasm-bindgen-macro"703
+version = "0.2.129"704
+source = "registry+https://github.com/rust-lang/crates.io-index"705
+checksum = "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535"706
+dependencies = [707
+ "quote",708
+ "wasm-bindgen-macro-support",709
+]710
+711
+[[package]]712
+name = "wasm-bindgen-macro-support"713
+version = "0.2.129"714
+source = "registry+https://github.com/rust-lang/crates.io-index"715
+checksum = "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7"716
+dependencies = [717
+ "bumpalo",718
+ "proc-macro2",719
+ "quote",720
+ "syn 3.0.9",721
+ "wasm-bindgen-shared",722
+]723
+724
+[[package]]725
+name = "wasm-bindgen-shared"726
+version = "0.2.129"727
+source = "registry+https://github.com/rust-lang/crates.io-index"728
+checksum = "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6"729
+dependencies = [730
+ "unicode-ident",731
+]732
+733
+[[package]]734
+name = "web-time"735
+version = "1.1.0"736
+source = "registry+https://github.com/rust-lang/crates.io-index"737
+checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"738
+dependencies = [739
+ "js-sys",740
+ "wasm-bindgen",741
+]742
+743
+[[package]]744
+name = "wildmatch"745
+version = "2.7.0"746
+source = "registry+https://github.com/rust-lang/crates.io-index"747
+checksum = "f18219fbd41a807dec044965d4106bb4fdb1d3a4b70aac4e5510aacc80a9f140"748
+749
+[[package]]750
+name = "winnow"751
+version = "1.0.4"752
+source = "registry+https://github.com/rust-lang/crates.io-index"753
+checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81"754
+dependencies = [755
+ "memchr",756
+]757
+758
+[[package]]759
+name = "writeable"760
+version = "0.6.4"761
+source = "registry+https://github.com/rust-lang/crates.io-index"762
+checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc"763
+764
+[[package]]765
+name = "yoke"766
+version = "0.8.4"767
+source = "registry+https://github.com/rust-lang/crates.io-index"768
+checksum = "417ef3fcf6c300b7dbd25c85531a746931c02ad536f3cf4786ed1e88223340b3"769
+dependencies = [770
+ "stable_deref_trait",771
+ "yoke-derive",772
+ "zerofrom",773
+]774
+775
+[[package]]776
+name = "yoke-derive"777
+version = "0.8.4"778
+source = "registry+https://github.com/rust-lang/crates.io-index"779
+checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71"780
+dependencies = [781
+ "proc-macro2",782
+ "quote",783
+ "syn 3.0.9",784
+ "synstructure",785
+]786
+787
+[[package]]788
+name = "zerofrom"789
+version = "0.1.8"790
+source = "registry+https://github.com/rust-lang/crates.io-index"791
+checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"792
+dependencies = [793
+ "zerofrom-derive",794
+]795
+796
+[[package]]797
+name = "zerofrom-derive"798
+version = "0.1.8"799
+source = "registry+https://github.com/rust-lang/crates.io-index"800
+checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a"801
+dependencies = [802
+ "proc-macro2",803
+ "quote",804
+ "syn 3.0.9",805
+ "synstructure",806
+]807
+808
+[[package]]809
+name = "zeroize"810
+version = "1.9.1"811
+source = "registry+https://github.com/rust-lang/crates.io-index"812
+checksum = "e13084392c5e4bc371903e2935a5eaeed24905a7511356b883835e18a78f6879"813
+814
+[[package]]815
+name = "zerotrie"816
+version = "0.2.5"817
+source = "registry+https://github.com/rust-lang/crates.io-index"818
+checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f"819
+dependencies = [820
+ "displaydoc",821
+ "yoke",822
+ "zerofrom",823
+]824
+825
+[[package]]826
+name = "zerovec"827
+version = "0.11.9"828
+source = "registry+https://github.com/rust-lang/crates.io-index"829
+checksum = "f58a2799cfe9a1670c7ea8edbd52ef8edb93cb37a7f83bf31ba9e35d9dae6a40"830
+dependencies = [831
+ "yoke",832
+ "zerofrom",833
+ "zerovec-derive",834
+]835
+836
+[[package]]837
+name = "zerovec-derive"838
+version = "0.11.7"839
+source = "registry+https://github.com/rust-lang/crates.io-index"840
+checksum = "c3743ddbf47738d929cd1ae2e199d40d0162979dfe31aef8ae646d2bf00bf97a"841
+dependencies = [842
+ "proc-macro2",843
+ "quote",844
+ "syn 3.0.9",845
+]846
+847
+[[package]]848
+name = "zmij"849
+version = "1.0.23"850
+source = "registry+https://github.com/rust-lang/crates.io-index"851
+checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"@@ -0,0 +1,13 @@
1
+[package]2
+name = "macltok-push-gateway"3
+version = "0.1.0"4
+edition = "2024"5
+description = "The Matrix push gateway wire format, without a Matrix client"6
+publish = false7
+8
+[workspace]9
+10
+[dependencies]11
+ruma-common = "0.19.0"12
+serde = { version = "1.0.219", features = ["derive"] }13
+serde_json = { version = "1.0", features = ["raw_value"] }@@ -0,0 +1,109 @@
1
+//! the homeserver side of `POST /_matrix/push/v1/notify`, for a gateway that holds no session2
+3
+use ruma_common::{OwnedEventId, OwnedRoomAliasId, OwnedRoomId, OwnedUserId};4
+use serde::{Deserialize, Serialize};5
+use serde_json::{Map, Value, value::RawValue};6
+7
+#[derive(Clone, Debug, Deserialize)]8
+#[non_exhaustive]9
+pub struct GatewayNotification {10
+ pub event_id: Option<OwnedEventId>,11
+ pub room_id: Option<OwnedRoomId>,12
+ #[serde(rename = "type")]13
+ pub event_type: Option<String>,14
+ pub sender: Option<OwnedUserId>,15
+ pub sender_display_name: Option<String>,16
+ pub room_name: Option<String>,17
+ pub room_alias: Option<OwnedRoomAliasId>,18
+ #[serde(default)]19
+ pub user_is_target: bool,20
+ #[serde(default)]21
+ pub prio: NotifyPrio,22
+ /// only in the full format, and still encrypted for an encrypted room23
+ pub content: Option<Box<RawValue>>,24
+ #[serde(default)]25
+ pub counts: NotifyCounts,26
+ #[serde(default)]27
+ pub devices: Vec<GatewayDevice>,28
+}29
+30
+impl GatewayNotification {31
+ /// a count-only push carries no event, and iOS punishes a web push that shows nothing32
+ pub fn is_event(&self) -> bool {33
+ self.event_id.is_some()34
+ }35
+}36
+37
+#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq)]38
+#[serde(rename_all = "lowercase")]39
+pub enum NotifyPrio {40
+ #[default]41
+ High,42
+ Low,43
+}44
+45
+#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq)]46
+#[non_exhaustive]47
+pub struct NotifyCounts {48
+ #[serde(default)]49
+ pub unread: u64,50
+ #[serde(default)]51
+ pub missed_calls: u64,52
+}53
+54
+#[derive(Clone, Debug, Deserialize)]55
+#[non_exhaustive]56
+pub struct GatewayDevice {57
+ pub app_id: String,58
+ pub pushkey: String,59
+ pub pushkey_ts: Option<u64>,60
+ /// the pusher's data as it was set, `format` included61
+ #[serde(default)]62
+ pub data: Map<String, Value>,63
+ #[serde(default)]64
+ pub tweaks: Map<String, Value>,65
+}66
+67
+#[derive(Deserialize)]68
+struct NotifyBody {69
+ notification: GatewayNotification,70
+}71
+72
+pub fn parse_notify(body: &[u8]) -> Result<GatewayNotification, serde_json::Error> {73
+ serde_json::from_slice::<NotifyBody>(body).map(|body| body.notification)74
+}75
+76
+/// the pushkeys the homeserver should drop, such as one whose web push endpoint answered 404 or 41077
+pub fn notify_response(rejected: &[String]) -> Vec<u8> {78
+ #[derive(Serialize)]79
+ struct Response<'a> {80
+ rejected: &'a [String],81
+ }82
+ serde_json::to_vec(&Response { rejected }).expect("a list of strings serialises")83
+}84
+85
+#[cfg(test)]86
+mod tests {87
+ use super::*;88
+89
+ #[test]90
+ fn a_count_only_push_is_no_event_and_devices_keep_their_data() {91
+ let body = br#"{"notification":{"counts":{"unread":2},"devices":[{"app_id":"me.malice","pushkey":"https://push.example/abc","data":{"format":"event_id_only","endpoint":"https://push.example/abc","auth":"secret"},"tweaks":{"sound":"default"}}]}}"#;92
+ let notification = parse_notify(body).unwrap();93
+ assert!(!notification.is_event());94
+ assert_eq!(notification.counts.unread, 2);95
+ assert_eq!(notification.prio, NotifyPrio::High);96
+ assert_eq!(notification.devices[0].data["auth"], "secret");97
+ assert_eq!(notification.devices[0].tweaks["sound"], "default");98
+99
+ let body = br#"{"notification":{"event_id":"$e","room_id":"!r:example.org","type":"m.room.message","sender":"@a:example.org","prio":"low","content":{"body":"hi"},"devices":[]}}"#;100
+ let notification = parse_notify(body).unwrap();101
+ assert!(notification.is_event());102
+ assert_eq!(notification.prio, NotifyPrio::Low);103
+ assert_eq!(notification.content.unwrap().get(), r#"{"body":"hi"}"#);104
+ assert_eq!(105
+ notify_response(&["gone".to_owned()]),106
+ br#"{"rejected":["gone"]}"#107
+ );108
+ }109
+}@@ -754,12 +754,17 @@ impl Engine {
754754
let client = self.client.clone();755755
match command {756756
Command::Lifecycle(LifecycleCommand::Shutdown) => return Some(reply),757
- Command::Account(AccountCommand::Logout) => {757
+ Command::Account(AccountCommand::Logout { remove_pushers }) => {758758
let events = self.port.event_sender();759759
let stop = self.stop.clone();760760
let logouts = self.logouts.clone();761761
logouts.send_modify(|logouts| logouts.in_flight += 1);762762
self.spawn_command("logout", reply, async move {763
+ for pusher in remove_pushers {764
+ if let Err(error) = crate::transport::remove_pusher(&client, pusher).await {765
+ tracing::debug!(%error, "removing a pusher before logout failed");766
+ }767
+ }763768
let result = client.logout().await;764769
if result.is_ok() {765770
let _ = events.send(Event::LoggedOut).await;@@ -60,21 +60,22 @@ pub use model::{
6060
AccountCommand, AttachmentEncryption, AttachmentUpload, Change, Command, CommandOutput,6161
ConnectionState, CreateRoomOptions, EncryptionCommand, EncryptionState, EngineErrorKind,6262
EngineFailure, Event, EventContext, EventContextCloseReason, EventContextCommand,63
- EventContextPage, EventContextSession, EventRef, HistoryState, ImagePack, ImagePackSource,64
- ImagePacks, KeyBackupState, LatestEvent, LifecycleCommand, LinkPreview, LinkPreviewImage,65
- Media, MediaCommand, MediaDescriptor, MediaFile, MediaId, MediaKind, MediaLocation, MediaSize,66
- MemberFilter, MemberMembership, MemberSummary, MembershipChange, Message, MessageContent,67
- MessageEditContent, MessageKind, MessageMentions, NotificationCommand, OwnDevice, PackCommand,68
- PackImage, PackImageInfo, PackUsage, Patch, PowerLevelChanges, Profile, PushNotification,69
- PushNotificationEvent, PushNotificationRoom, PushNotificationSender, PushNotificationStatus,70
- Reaction, RecentHistoryState, RecoveryKey, RecoveryState, ReplyDetails, ReplyReference, Retain,71
- RichText, RoomCategory, RoomCommand, RoomHero, RoomListFilter, RoomMatcher, RoomMembership,72
- RoomNotificationMode, RoomNotificationSettings, RoomPowerLevels, RoomPreset, RoomSummary,73
- RoomVisibility, SendState, Sender, SpaceChild, Termination, ThreadListCloseReason,74
- ThreadListCommand, ThreadListEntry, ThreadSummary, ThreadUnread, TimelineCommand,75
- TimelineContent, TimelineDiff, TimelineDiffError, TimelineEvent, TimelineId, TimelineItem,76
- TimelineItemId, TypingState, UploadDetails, UploadOutcome, UploadThumbnail, UtdCause,77
- VerificationAction, VerificationFailure, VerificationState, VerificationTarget,63
+ EventContextPage, EventContextSession, EventRef, HistoryState, HttpPusher, ImagePack,64
+ ImagePackSource, ImagePacks, KeyBackupState, LatestEvent, LifecycleCommand, LinkPreview,65
+ LinkPreviewImage, Media, MediaCommand, MediaDescriptor, MediaFile, MediaId, MediaKind,66
+ MediaLocation, MediaSize, MemberFilter, MemberMembership, MemberSummary, MembershipChange,67
+ Message, MessageContent, MessageEditContent, MessageKind, MessageMentions, NotificationCommand,68
+ OwnDevice, PackCommand, PackImage, PackImageInfo, PackUsage, Patch, PowerLevelChanges, Profile,69
+ PushFormat, PushNotification, PushNotificationEvent, PushNotificationRoom,70
+ PushNotificationSender, PushNotificationStatus, PusherKey, Reaction, RecentHistoryState,71
+ RecoveryKey, RecoveryState, ReplyDetails, ReplyReference, Retain, RichText, RoomCategory,72
+ RoomCommand, RoomHero, RoomListFilter, RoomMatcher, RoomMembership, RoomNotificationMode,73
+ RoomNotificationSettings, RoomPowerLevels, RoomPreset, RoomSummary, RoomVisibility, SendState,74
+ Sender, SpaceChild, Termination, ThreadListCloseReason, ThreadListCommand, ThreadListEntry,75
+ ThreadSummary, ThreadUnread, TimelineCommand, TimelineContent, TimelineDiff, TimelineDiffError,76
+ TimelineEvent, TimelineId, TimelineItem, TimelineItemId, TypingState, UploadDetails,77
+ UploadOutcome, UploadThumbnail, UtdCause, VerificationAction, VerificationFailure,78
+ VerificationState, VerificationTarget,7879
};7980
pub use repair_model::{8081
HistoryContinuity, HistoryGap, HistoryGapLifecycle, HistoryGapPause, HistoryRepairCommand,@@ -66,7 +66,11 @@ pub enum EventContextCommand {
6666
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]6767
#[non_exhaustive]6868
pub enum AccountCommand {69
- Logout,69
+ /// removes `remove_pushers` first, best effort, while the token still works. pushers belong70
+ /// to the user rather than the device, so only the caller knows which are this browser's71
+ Logout {72
+ remove_pushers: Vec<PusherKey>,73
+ },7074
SetAccountData {7175
event_type: GlobalAccountDataEventType,7276
content: Raw<AnyGlobalAccountDataEventContent>,@@ -1271,6 +1275,9 @@ pub struct PushNotificationSender {
12711275
#[non_exhaustive]12721276
pub struct PushNotificationRoom {12731277
pub room_id: OwnedRoomId,1278
+ /// from this session's store, so `None` for a room it hasn't synced yet1279
+ pub unread_notifications: Option<u64>,1280
+ pub unread_mentions: Option<u64>,12741281
pub name: String,12751282
pub avatar_url: Option<MediaId>,12761283
pub canonical_alias: Option<OwnedRoomAliasId>,@@ -2417,3 +2424,31 @@ pub enum EngineErrorKind {
24172424
Watcher,24182425
Other,24192426
}2427
+2428
+#[derive(Clone, Debug, Eq, PartialEq)]2429
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]2430
+pub struct PusherKey {2431
+ pub app_id: String,2432
+ pub pushkey: String,2433
+}2434
+2435
+#[derive(Clone, Debug, PartialEq)]2436
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]2437
+pub struct HttpPusher {2438
+ pub app_id: String,2439
+ pub pushkey: String,2440
+ pub app_display_name: String,2441
+ pub device_display_name: String,2442
+ pub lang: String,2443
+ pub url: String,2444
+ pub format: PushFormat,2445
+ /// sent beside `url` and `format` in the pusher's data, and back to the gateway in every push2446
+ pub data: serde_json::Map<String, serde_json::Value>,2447
+}2448
+2449
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]2450
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]2451
+pub enum PushFormat {2452
+ Full,2453
+ EventIdOnly,2454
+}@@ -29,16 +29,17 @@ use tokio::sync::{OnceCell, mpsc, oneshot, watch};
2929
use crate::{3030
AccountCommand, AttachmentUpload, Command, CommandOutput, ConnectionState, CreateRoomOptions,3131
EncryptionCommand, EncryptionState, Error, ErrorKind, Event, EventContextCommand,32
- EventContextPage, EventContextSession, EventRef, HistoryRepairCommand, ImagePackSource,33
- ImagePacks, InteractiveAuth, InteractiveAuthOutcome, LifecycleCommand, LinkPreview, Media,34
- MediaCommand, MediaId, MediaLocation, MediaSize, MemberFilter, MemberSummary, MentionKey,35
- MentionsBoundary, MentionsCommand, MentionsPage, MessageContent, MessageEditContent,36
- NotificationCommand, OwnDevice, PackCommand, PackImageInfo, PackUsage, Patch,37
- PowerLevelChanges, Profile, PushNotification, PushNotificationEvent, PushNotificationStatus,38
- RecoveryKey, RoomCommand, RoomListFilter, RoomNotificationMode, RoomNotificationSettings,39
- RoomPowerLevels, RoomSummary, SavedMentionContext, SearchCommand, SearchCoverage, SearchPage,40
- SearchScope, SearchSession, SpaceChild, ThreadListCommand, TimelineCommand, TimelineId,41
- VerificationAction, VerificationTarget,32
+ EventContextPage, EventContextSession, EventRef, HistoryRepairCommand, HttpPusher,33
+ ImagePackSource, ImagePacks, InteractiveAuth, InteractiveAuthOutcome, LifecycleCommand,34
+ LinkPreview, Media, MediaCommand, MediaId, MediaLocation, MediaSize, MemberFilter,35
+ MemberSummary, MentionKey, MentionsBoundary, MentionsCommand, MentionsPage, MessageContent,36
+ MessageEditContent, NotificationCommand, OwnDevice, PackCommand, PackImageInfo, PackUsage,37
+ Patch, PowerLevelChanges, Profile, PushFormat, PushNotification, PushNotificationEvent,38
+ PushNotificationStatus, PusherKey, RecoveryKey, RoomCommand, RoomListFilter,39
+ RoomNotificationMode, RoomNotificationSettings, RoomPowerLevels, RoomSummary,40
+ SavedMentionContext, SearchCommand, SearchCoverage, SearchPage, SearchScope, SearchSession,41
+ SpaceChild, ThreadListCommand, TimelineCommand, TimelineId, VerificationAction,42
+ VerificationTarget,4243
encryption::encryption_state,4344
engine::{MediaService, StoreLock},4445
model::{PushNotificationRoom, PushNotificationSender},@@ -149,8 +150,73 @@ impl ClientHandle {
149150
.await150151
}151152
152
- pub async fn logout(&self) -> Result<(), Error> {153
- self.run(Command::Account(AccountCommand::Logout)).await153
+ pub async fn logout(&self, remove_pushers: Vec<PusherKey>) -> Result<(), Error> {154
+ self.run(Command::Account(AccountCommand::Logout { remove_pushers }))155
+ .await156
+ }157
+158
+ /// replaces any pusher with the same app id and pushkey159
+ pub async fn set_pusher(&self, pusher: HttpPusher) -> Result<(), Error> {160
+ use ruma::{161
+ api::client::push::{PusherIds, PusherInit, PusherKind},162
+ push::{HttpPusherData, PushFormat as SdkFormat},163
+ };164
+ let mut data = HttpPusherData::new(pusher.url);165
+ data.format = match pusher.format {166
+ PushFormat::Full => None,167
+ PushFormat::EventIdOnly => Some(SdkFormat::EventIdOnly),168
+ };169
+ data.data = pusher.data;170
+ let pusher = PusherInit {171
+ ids: PusherIds::new(pusher.pushkey, pusher.app_id),172
+ kind: PusherKind::Http(data),173
+ app_display_name: pusher.app_display_name,174
+ device_display_name: pusher.device_display_name,175
+ profile_tag: None,176
+ lang: pusher.lang,177
+ };178
+ self.client179
+ .pusher()180
+ .set(pusher.into(), false)181
+ .await182
+ .map_err(|source| Error::from_sdk("setting the pusher failed", source))183
+ }184
+185
+ pub async fn remove_pusher(&self, pusher: PusherKey) -> Result<(), Error> {186
+ remove_pusher(&self.client, pusher).await187
+ }188
+189
+ /// the account's http pushers, every device's alike190
+ pub async fn pushers(&self) -> Result<Vec<HttpPusher>, Error> {191
+ use ruma::{192
+ api::client::push::{PusherKind, get_pushers},193
+ push::PushFormat as SdkFormat,194
+ };195
+ let response = self196
+ .client197
+ .send(get_pushers::v3::Request::new())198
+ .await199
+ .map_err(|source| Error::from_sdk("fetching pushers failed", source.into()))?;200
+ Ok(response201
+ .pushers202
+ .into_iter()203
+ .filter_map(|pusher| match pusher.kind {204
+ PusherKind::Http(data) => Some(HttpPusher {205
+ app_id: pusher.ids.app_id,206
+ pushkey: pusher.ids.pushkey,207
+ app_display_name: pusher.app_display_name,208
+ device_display_name: pusher.device_display_name,209
+ lang: pusher.lang,210
+ url: data.url,211
+ format: match data.format {212
+ Some(SdkFormat::EventIdOnly) => PushFormat::EventIdOnly,213
+ _ => PushFormat::Full,214
+ },215
+ data: data.data,216
+ }),217
+ _ => None,218
+ })219
+ .collect())154220
}155221
156222
pub async fn delete_devices(@@ -1341,7 +1407,13 @@ impl ClientHandle {
13411407
.get_notification(room_id, event_id)13421408
.await13431409
.map_err(notification_failed)?;1344
- Ok(normalise_push_notification(room_id, event_id, status))1410
+ let unread = self1411
+ .client1412
+ .get_room(room_id)1413
+ .map(|room| (room.num_unread_notifications(), room.num_unread_mentions()));1414
+ Ok(normalise_push_notification(1415
+ room_id, event_id, status, unread,1416
+ ))13451417
}13461418
13471419
pub async fn members(@@ -1844,6 +1916,7 @@ fn normalise_push_notification(
18441916
room_id: &RoomId,18451917
event_id: &EventId,18461918
status: NotificationStatus,1919
+ unread: Option<(u64, u64)>,18471920
) -> PushNotificationStatus {18481921
match status {18491922
NotificationStatus::Event(item) => {@@ -1864,6 +1937,8 @@ fn normalise_push_notification(
18641937
},18651938
room: PushNotificationRoom {18661939
room_id: room_id.to_owned(),1940
+ unread_notifications: unread.map(|(notifications, _)| notifications),1941
+ unread_mentions: unread.map(|(_, mentions)| mentions),18671942
name: item.room_computed_display_name,18681943
avatar_url: item.room_avatar_url.as_deref().map(MediaId::plain),18691944
canonical_alias: item@@ -1893,6 +1968,15 @@ fn normalise_push_notification(
18931968
}18941969
}18951970
1971
+pub(crate) async fn remove_pusher(client: &Client, pusher: PusherKey) -> Result<(), Error> {1972
+ use ruma::api::client::push::PusherIds;1973
+ client1974
+ .pusher()1975
+ .delete(PusherIds::new(pusher.pushkey, pusher.app_id))1976
+ .await1977
+ .map_err(|source| Error::from_sdk("removing the pusher failed", source))1978
+}1979
+18961980
fn unexpected(wanted: &str, output: &CommandOutput) -> Error {18971981
Error::new(18981982
ErrorKind::Other,