Files
nym/common/zulip-client/src/message/mod.rs
T
Jędrzej Stuczyński baddaaac22 feat: nym signers monitor (#5933)
* initialise nym-signers-monitor

* creating nyxd client

* performing checks

* sending notifications on failure

* rate limitting on notifications + clippy
2025-09-02 09:27:09 +01:00

268 lines
6.5 KiB
Rust

// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::message::to::{ToChannel, ToDirect};
use serde::{Deserialize, Serialize};
pub mod to;
#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "result")]
#[serde(rename_all = "snake_case")]
pub enum SendMessageResponse {
Success {
id: i64,
automatic_new_visibility_policy: Option<i64>,
msg: String,
},
Error {
code: String,
msg: String,
stream: Option<String>,
},
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
#[serde(tag = "type")]
pub enum SendableMessageContent {
// old name: 'private'
Direct {
// internally this is a list
to: String,
content: String,
},
// alternative name: 'channel'
Stream {
to: String,
topic: Option<String>,
content: String,
},
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
pub struct SendableMessage {
#[serde(flatten)]
content: SendableMessageContent,
/// For clients supporting local echo, the event queue ID for the client.
/// If passed, `local_id` is required. If the message is successfully sent,
/// the server will include `local_id` in the message event that the client with this `queue_id`
/// will receive notifying it of the new message via `GET /events`.
/// This lets the client know unambiguously that it should replace the locally echoed message,
/// rather than adding this new message
/// (which would be correct if the user had sent the new message from another device).
/// example: "fb67bf8a-c031-47cc-84cf-ed80accacda8"
queue_id: Option<String>,
/// For clients supporting local echo, a unique string-format identifier chosen freely by the client;
/// the server will pass it back to the client without inspecting it, as described in the `queue_id` description.
/// example: "100.01"
local_id: Option<String>,
/// Whether the message should be initially marked read by its sender.
/// If unspecified, the server uses a heuristic based on the client name.
read_by_sender: bool,
}
impl SendableMessage {
pub fn new(content: impl Into<SendableMessageContent>) -> Self {
SendableMessage {
content: content.into(),
queue_id: None,
local_id: None,
read_by_sender: false,
}
}
#[must_use]
pub fn with_queue(mut self, queue_id: impl Into<String>, local_id: impl Into<String>) -> Self {
self.queue_id = Some(queue_id.into());
self.local_id = Some(local_id.into());
self
}
#[must_use]
pub fn read_by_sender(mut self, read_by_sender: bool) -> Self {
self.read_by_sender = read_by_sender;
self
}
}
pub type PrivateMessage = DirectMessage;
pub struct DirectMessage {
to: String,
content: String,
}
impl DirectMessage {
pub fn new(to: impl Into<ToDirect>, content: impl Into<String>) -> Self {
DirectMessage {
to: to.into().to_string(),
content: content.into(),
}
}
}
pub type ChannelMessage = StreamMessage;
pub struct StreamMessage {
to: String,
topic: Option<String>,
content: String,
}
impl StreamMessage {
pub fn new(
to: impl Into<ToChannel>,
content: impl Into<String>,
topic: impl IntoMaybeTopic,
) -> Self {
StreamMessage {
to: to.into().to_string(),
topic: topic.into_maybe_topic(),
content: content.into(),
}
}
pub fn no_topic(to: impl Into<ToChannel>, content: impl Into<String>) -> Self {
Self::new(to, content, None::<String>)
}
#[must_use]
pub fn with_topic(mut self, topic: impl Into<String>) -> Self {
self.topic = Some(topic.into());
self
}
}
impl From<SendableMessageContent> for SendableMessage {
fn from(content: SendableMessageContent) -> Self {
SendableMessage::new(content)
}
}
impl From<DirectMessage> for SendableMessage {
fn from(msg: DirectMessage) -> Self {
SendableMessageContent::from(msg).into()
}
}
impl From<DirectMessage> for SendableMessageContent {
fn from(msg: DirectMessage) -> Self {
SendableMessageContent::Direct {
to: msg.to,
content: msg.content,
}
}
}
impl<T, S> From<(T, S)> for DirectMessage
where
T: Into<ToDirect>,
S: Into<String>,
{
fn from((to, content): (T, S)) -> Self {
DirectMessage::new(to, content)
}
}
impl<T, S> From<(T, S)> for SendableMessage
where
T: Into<ToDirect>,
S: Into<String>,
{
fn from((to, content): (T, S)) -> Self {
DirectMessage::new(to, content).into()
}
}
impl From<StreamMessage> for SendableMessage {
fn from(msg: StreamMessage) -> Self {
SendableMessageContent::from(msg).into()
}
}
impl From<StreamMessage> for SendableMessageContent {
fn from(msg: StreamMessage) -> Self {
SendableMessageContent::Stream {
to: msg.to,
topic: msg.topic,
content: msg.content,
}
}
}
impl<T, S, U> From<(T, S, U)> for StreamMessage
where
T: Into<ToChannel>,
S: Into<String>,
U: IntoMaybeTopic,
{
fn from((to, content, topic): (T, S, U)) -> Self {
StreamMessage::new(to, content, topic)
}
}
impl<T, S> From<(T, S)> for StreamMessage
where
T: Into<ToChannel>,
S: Into<String>,
{
fn from((to, content): (T, S)) -> Self {
StreamMessage::no_topic(to, content)
}
}
impl<T, S, U> From<(T, S, U)> for SendableMessage
where
T: Into<ToChannel>,
S: Into<String>,
U: IntoMaybeTopic,
{
fn from(inner: (T, S, U)) -> Self {
StreamMessage::from(inner).into()
}
}
pub trait IntoMaybeTopic {
fn into_maybe_topic(self) -> Option<String>;
}
impl<S> IntoMaybeTopic for &Option<S>
where
S: Into<String> + Clone,
{
fn into_maybe_topic(self) -> Option<String> {
self.clone().map(|s| s.into())
}
}
impl<S> IntoMaybeTopic for Option<S>
where
S: Into<String>,
{
fn into_maybe_topic(self) -> Option<String> {
self.map(Into::into)
}
}
impl IntoMaybeTopic for String {
fn into_maybe_topic(self) -> Option<String> {
Some(self)
}
}
impl IntoMaybeTopic for &String {
fn into_maybe_topic(self) -> Option<String> {
Some(self.clone())
}
}
impl IntoMaybeTopic for &str {
fn into_maybe_topic(self) -> Option<String> {
Some(self.to_string())
}
}