Add 'ruma-common/' from commit 'b516c0cd72c1a5e9985905f60b956c5365cd8789'
git-subtree-dir: ruma-common git-subtree-mainline: c186f0f8c9c542fd1c7cea464de1ae94e5bd32ba git-subtree-split: b516c0cd72c1a5e9985905f60b956c5365cd8789
This commit is contained in:
commit
40b51d73a3
27
ruma-common/.builds/beta.yml
Normal file
27
ruma-common/.builds/beta.yml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
image: archlinux
|
||||||
|
packages:
|
||||||
|
- rustup
|
||||||
|
sources:
|
||||||
|
- https://github.com/ruma/ruma-common
|
||||||
|
tasks:
|
||||||
|
- rustup: |
|
||||||
|
# We specify --profile minimal because we'd otherwise download docs
|
||||||
|
rustup toolchain install beta --profile minimal -c rustfmt -c clippy
|
||||||
|
rustup default beta
|
||||||
|
- test: |
|
||||||
|
cd ruma-common
|
||||||
|
|
||||||
|
# We don't want the build to stop on individual failure of independent
|
||||||
|
# tools, so capture tool exit codes and set the task exit code manually
|
||||||
|
set +e
|
||||||
|
|
||||||
|
cargo fmt -- --check
|
||||||
|
fmt_exit=$?
|
||||||
|
|
||||||
|
cargo clippy --all-targets --all-features -- -D warnings
|
||||||
|
clippy_exit=$?
|
||||||
|
|
||||||
|
cargo test --verbose
|
||||||
|
test_exit=$?
|
||||||
|
|
||||||
|
exit $(( $fmt_exit || $clippy_exit || $test_exit ))
|
16
ruma-common/.builds/msrv.yml
Normal file
16
ruma-common/.builds/msrv.yml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
image: archlinux
|
||||||
|
packages:
|
||||||
|
- rustup
|
||||||
|
sources:
|
||||||
|
- https://github.com/ruma/ruma-common
|
||||||
|
tasks:
|
||||||
|
- rustup: |
|
||||||
|
# We specify --profile minimal because we'd otherwise download docs
|
||||||
|
rustup toolchain install 1.40.0 --profile minimal
|
||||||
|
rustup default 1.40.0
|
||||||
|
- test: |
|
||||||
|
cd ruma-common
|
||||||
|
|
||||||
|
# Only make sure the code builds with the MSRV. Tests can require later
|
||||||
|
# Rust versions, don't compile or run them.
|
||||||
|
cargo build --verbose
|
32
ruma-common/.builds/nightly.yml
Normal file
32
ruma-common/.builds/nightly.yml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
image: archlinux
|
||||||
|
packages:
|
||||||
|
- rustup
|
||||||
|
sources:
|
||||||
|
- https://github.com/ruma/ruma-common
|
||||||
|
tasks:
|
||||||
|
- rustup: |
|
||||||
|
rustup toolchain install nightly --profile minimal
|
||||||
|
rustup default nightly
|
||||||
|
|
||||||
|
# Try installing rustfmt & clippy for nightly, but don't fail the build
|
||||||
|
# if they are not available
|
||||||
|
rustup component add rustfmt || true
|
||||||
|
rustup component add clippy || true
|
||||||
|
- test: |
|
||||||
|
cd ruma-common
|
||||||
|
|
||||||
|
# We don't want the build to stop on individual failure of independent
|
||||||
|
# tools, so capture tool exit codes and set the task exit code manually
|
||||||
|
set +e
|
||||||
|
|
||||||
|
if ( rustup component list | grep -q rustfmt ); then
|
||||||
|
cargo fmt -- --check
|
||||||
|
fi
|
||||||
|
fmt_exit=$?
|
||||||
|
|
||||||
|
if ( rustup component list | grep -q clippy ); then
|
||||||
|
cargo clippy --all-targets --all-features -- -D warnings
|
||||||
|
fi
|
||||||
|
clippy_exit=$?
|
||||||
|
|
||||||
|
exit $(( $fmt_exit || $clippy_exit ))
|
29
ruma-common/.builds/stable.yml
Normal file
29
ruma-common/.builds/stable.yml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
image: archlinux
|
||||||
|
packages:
|
||||||
|
- rustup
|
||||||
|
sources:
|
||||||
|
- https://github.com/ruma/ruma-common
|
||||||
|
tasks:
|
||||||
|
- rustup: |
|
||||||
|
# We specify --profile minimal because we'd otherwise download docs
|
||||||
|
rustup toolchain install stable --profile minimal -c rustfmt -c clippy
|
||||||
|
rustup default stable
|
||||||
|
- test: |
|
||||||
|
cd ruma-common
|
||||||
|
|
||||||
|
# We don't want the build to stop on individual failure of independent
|
||||||
|
# tools, so capture tool exit codes and set the task exit code manually
|
||||||
|
set +e
|
||||||
|
|
||||||
|
cargo fmt -- --check
|
||||||
|
fmt_exit=$?
|
||||||
|
|
||||||
|
cargo clippy --all-targets --all-features -- -D warnings
|
||||||
|
clippy_exit=$?
|
||||||
|
|
||||||
|
cargo test --verbose
|
||||||
|
test_exit=$?
|
||||||
|
|
||||||
|
exit $(( $fmt_exit || $clippy_exit || $test_exit ))
|
||||||
|
# TODO: Add audit task once cargo-audit binary releases are available.
|
||||||
|
# See https://github.com/RustSec/cargo-audit/issues/66
|
2
ruma-common/.gitignore
vendored
Normal file
2
ruma-common/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/target
|
||||||
|
Cargo.lock
|
18
ruma-common/Cargo.toml
Normal file
18
ruma-common/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "ruma-common"
|
||||||
|
version = "0.1.3"
|
||||||
|
authors = ["Jonas Platte <jplatte@posteo.de>"]
|
||||||
|
description = "Common types for other ruma crates."
|
||||||
|
homepage = "https://github.com/ruma/ruma-common"
|
||||||
|
keywords = ["matrix", "chat", "messaging", "ruma"]
|
||||||
|
license = "MIT"
|
||||||
|
readme = "README.md"
|
||||||
|
repository = "https://github.com/ruma/ruma-client-api"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
matches = "0.1.8"
|
||||||
|
ruma-serde = "0.2.2"
|
||||||
|
serde = { version = "1.0.111", features = ["derive"] }
|
||||||
|
serde_json = { version = "1.0.53", features = ["raw_value"] }
|
||||||
|
strum = { version = "0.18.0", features = ["derive"] }
|
19
ruma-common/LICENSE
Normal file
19
ruma-common/LICENSE
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2020 Jonas Platte
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
7
ruma-common/README.md
Normal file
7
ruma-common/README.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# ruma-common
|
||||||
|
|
||||||
|
Common types for other ruma crates.
|
||||||
|
|
||||||
|
This crate is meant to be a dependency for other ruma crates only, consumers of
|
||||||
|
those crates should never have to use this directly (its types will be
|
||||||
|
re-exported from the other crates).
|
6
ruma-common/src/lib.rs
Normal file
6
ruma-common/src/lib.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
//! Common types for other ruma crates.
|
||||||
|
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
|
pub mod presence;
|
||||||
|
pub mod push;
|
27
ruma-common/src/presence.rs
Normal file
27
ruma-common/src/presence.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//! Common types for the [presence module][presence]
|
||||||
|
//!
|
||||||
|
//! [presence]: https://matrix.org/docs/spec/client_server/r0.6.1#id62
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use strum::{Display, EnumString};
|
||||||
|
|
||||||
|
/// A description of a user's connectivity and availability for chat.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Display, EnumString, Deserialize, Serialize)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
#[strum(serialize_all = "snake_case")]
|
||||||
|
pub enum PresenceState {
|
||||||
|
/// Disconnected from the service.
|
||||||
|
Offline,
|
||||||
|
|
||||||
|
/// Connected to the service.
|
||||||
|
Online,
|
||||||
|
|
||||||
|
/// Connected to the service but not available for chat.
|
||||||
|
Unavailable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PresenceState {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Online
|
||||||
|
}
|
||||||
|
}
|
193
ruma-common/src/push.rs
Normal file
193
ruma-common/src/push.rs
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
//! Common types for the [push notifications module][push]
|
||||||
|
//!
|
||||||
|
//! [push]: https://matrix.org/docs/spec/client_server/r0.6.0#id89
|
||||||
|
|
||||||
|
use std::fmt::{self, Formatter};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
use serde_json::value::RawValue as RawJsonValue;
|
||||||
|
|
||||||
|
mod tweak_serde;
|
||||||
|
|
||||||
|
/// This represents the different actions that should be taken when a rule is matched, and
|
||||||
|
/// controls how notifications are delivered to the client.
|
||||||
|
///
|
||||||
|
/// See https://matrix.org/docs/spec/client_server/r0.6.0#actions for details.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum Action {
|
||||||
|
/// Causes matching events to generate a notification.
|
||||||
|
Notify,
|
||||||
|
|
||||||
|
/// Prevents matching events from generating a notification.
|
||||||
|
DontNotify,
|
||||||
|
|
||||||
|
/// Behaves like notify but homeservers may choose to coalesce multiple events
|
||||||
|
/// into a single notification.
|
||||||
|
Coalesce,
|
||||||
|
|
||||||
|
/// Sets an entry in the 'tweaks' dictionary sent to the push gateway.
|
||||||
|
SetTweak(Tweak),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The `set_tweak` action.
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
#[serde(from = "tweak_serde::Tweak", into = "tweak_serde::Tweak")]
|
||||||
|
pub enum Tweak {
|
||||||
|
/// A string representing the sound to be played when this notification arrives.
|
||||||
|
///
|
||||||
|
/// A value of "default" means to play a default sound. A device may choose to alert the user by
|
||||||
|
/// some other means if appropriate, eg. vibration.
|
||||||
|
Sound(String),
|
||||||
|
|
||||||
|
/// A boolean representing whether or not this message should be highlighted in the UI.
|
||||||
|
///
|
||||||
|
/// This will normally take the form of presenting the message in a different color and/or
|
||||||
|
/// style. The UI might also be adjusted to draw particular attention to the room in which the
|
||||||
|
/// event occurred. If a `highlight` tweak is given with no value, its value is defined to be
|
||||||
|
/// `true`. If no highlight tweak is given at all then the value of `highlight` is defined to be
|
||||||
|
/// `false`.
|
||||||
|
Highlight(#[serde(default = "ruma_serde::default_true")] bool),
|
||||||
|
|
||||||
|
/// A custom tweak
|
||||||
|
Custom {
|
||||||
|
/// The name of the custom tweak (`set_tweak` field)
|
||||||
|
name: String,
|
||||||
|
|
||||||
|
/// The value of the custom tweak
|
||||||
|
value: Box<RawJsonValue>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Action {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
use serde::de::{MapAccess, Visitor};
|
||||||
|
|
||||||
|
struct ActionVisitor;
|
||||||
|
impl<'de> Visitor<'de> for ActionVisitor {
|
||||||
|
type Value = Action;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(formatter, "a valid action object")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Match a simple action type
|
||||||
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
match v {
|
||||||
|
"notify" => Ok(Action::Notify),
|
||||||
|
"dont_notify" => Ok(Action::DontNotify),
|
||||||
|
"coalesce" => Ok(Action::Coalesce),
|
||||||
|
s => Err(E::unknown_variant(
|
||||||
|
&s,
|
||||||
|
&["notify", "dont_notify", "coalesce"],
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Match the more complex set_tweaks action object as a key-value map
|
||||||
|
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
|
||||||
|
where
|
||||||
|
A: MapAccess<'de>,
|
||||||
|
{
|
||||||
|
Tweak::deserialize(serde::de::value::MapAccessDeserializer::new(map))
|
||||||
|
.map(Action::SetTweak)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_any(ActionVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for Action {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Action::Notify => serializer.serialize_unit_variant("Action", 0, "notify"),
|
||||||
|
Action::DontNotify => serializer.serialize_unit_variant("Action", 1, "dont_notify"),
|
||||||
|
Action::Coalesce => serializer.serialize_unit_variant("Action", 2, "coalesce"),
|
||||||
|
Action::SetTweak(kind) => kind.serialize(serializer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use matches::assert_matches;
|
||||||
|
use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
|
||||||
|
|
||||||
|
use super::{Action, Tweak};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_string_action() {
|
||||||
|
assert_eq!(to_json_value(&Action::Notify).unwrap(), json!("notify"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_tweak_sound_action() {
|
||||||
|
assert_eq!(
|
||||||
|
to_json_value(&Action::SetTweak(Tweak::Sound("default".into()))).unwrap(),
|
||||||
|
json!({ "set_tweak": "sound", "value": "default" })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_tweak_highlight_action() {
|
||||||
|
assert_eq!(
|
||||||
|
to_json_value(&Action::SetTweak(Tweak::Highlight(true))).unwrap(),
|
||||||
|
json!({ "set_tweak": "highlight" })
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
to_json_value(&Action::SetTweak(Tweak::Highlight(false))).unwrap(),
|
||||||
|
json!({ "set_tweak": "highlight", "value": false })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_string_action() {
|
||||||
|
assert_matches!(
|
||||||
|
from_json_value::<Action>(json!("notify")).unwrap(),
|
||||||
|
Action::Notify
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_tweak_sound_action() {
|
||||||
|
let json_data = json!({
|
||||||
|
"set_tweak": "sound",
|
||||||
|
"value": "default"
|
||||||
|
});
|
||||||
|
assert_matches!(
|
||||||
|
&from_json_value::<Action>(json_data).unwrap(),
|
||||||
|
Action::SetTweak(Tweak::Sound(value)) if value == "default"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_tweak_highlight_action() {
|
||||||
|
let json_data = json!({
|
||||||
|
"set_tweak": "highlight",
|
||||||
|
"value": true
|
||||||
|
});
|
||||||
|
assert_matches!(
|
||||||
|
from_json_value::<Action>(json_data).unwrap(),
|
||||||
|
Action::SetTweak(Tweak::Highlight(true))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_tweak_highlight_action_with_default_value() {
|
||||||
|
assert_matches!(
|
||||||
|
from_json_value::<Action>(json!({ "set_tweak": "highlight" })).unwrap(),
|
||||||
|
Action::SetTweak(Tweak::Highlight(true))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
55
ruma-common/src/push/tweak_serde.rs
Normal file
55
ruma-common/src/push/tweak_serde.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::value::RawValue as RawJsonValue;
|
||||||
|
|
||||||
|
/// Values for the `set_tweak` action.
|
||||||
|
#[derive(Clone, Deserialize, Serialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum Tweak {
|
||||||
|
Sound(SoundTweak),
|
||||||
|
Highlight(HighlightTweak),
|
||||||
|
Custom {
|
||||||
|
#[serde(rename = "set_tweak")]
|
||||||
|
name: String,
|
||||||
|
value: Box<RawJsonValue>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
#[serde(tag = "set_tweak", rename = "sound")]
|
||||||
|
pub struct SoundTweak {
|
||||||
|
value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
#[serde(tag = "set_tweak", rename = "highlight")]
|
||||||
|
pub struct HighlightTweak {
|
||||||
|
#[serde(
|
||||||
|
default = "ruma_serde::default_true",
|
||||||
|
skip_serializing_if = "ruma_serde::is_true"
|
||||||
|
)]
|
||||||
|
value: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<super::Tweak> for Tweak {
|
||||||
|
fn from(tweak: super::Tweak) -> Self {
|
||||||
|
use super::Tweak::*;
|
||||||
|
|
||||||
|
match tweak {
|
||||||
|
Sound(value) => Self::Sound(SoundTweak { value }),
|
||||||
|
Highlight(value) => Self::Highlight(HighlightTweak { value }),
|
||||||
|
Custom { name, value } => Self::Custom { name, value },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Tweak> for super::Tweak {
|
||||||
|
fn from(tweak: Tweak) -> Self {
|
||||||
|
use Tweak::*;
|
||||||
|
|
||||||
|
match tweak {
|
||||||
|
Sound(SoundTweak { value }) => Self::Sound(value),
|
||||||
|
Highlight(HighlightTweak { value }) => Self::Highlight(value),
|
||||||
|
Custom { name, value } => Self::Custom { name, value },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user