Private
Public Access
1
0

client: implements send_message

This commit is contained in:
2025-05-02 12:03:56 -07:00
parent 2106bce755
commit 07b55f8615
6 changed files with 133 additions and 9 deletions

View File

@@ -20,7 +20,17 @@ use tokio_tungstenite::connect_async;
use tokio_tungstenite::{MaybeTlsStream, WebSocketStream};
use crate::{
model::{Conversation, ConversationID, JwtToken, Message, MessageID, UpdateItem, Event},
model::{
Conversation,
ConversationID,
JwtToken,
Message,
MessageID,
UpdateItem,
Event,
OutgoingMessage,
},
APIInterface
};
@@ -215,6 +225,19 @@ impl<K: AuthenticationStore + Send + Sync> APIInterface for HTTPAPIClient<K> {
Ok(messages)
}
async fn send_message(
&mut self,
outgoing_message: OutgoingMessage,
) -> Result<Message, Self::Error> {
let message: Message = self.request_with_body(
"sendMessage",
Method::POST,
|| serde_json::to_string(&outgoing_message).unwrap().into()
).await?;
Ok(message)
}
async fn open_event_socket(&mut self) -> Result<WebsocketEventSocket, Self::Error> {
use tungstenite::http::StatusCode;
use tungstenite::handshake::client::Request as TungsteniteRequest;
@@ -285,24 +308,23 @@ impl<K: AuthenticationStore + Send + Sync> HTTPAPIClient<K> {
}
async fn request<T: DeserializeOwned>(&mut self, endpoint: &str, method: Method) -> Result<T, Error> {
self.request_with_body(endpoint, method, || { Body::empty() }).await
self.request_with_body(endpoint, method, Body::empty).await
}
async fn request_with_body<T, B>(&mut self, endpoint: &str, method: Method, body_fn: B) -> Result<T, Error>
where T: DeserializeOwned, B: Fn() -> Body
async fn request_with_body<T>(&mut self, endpoint: &str, method: Method, body_fn: impl Fn() -> Body) -> Result<T, Error>
where T: DeserializeOwned
{
self.request_with_body_retry(endpoint, method, body_fn, true).await
}
async fn request_with_body_retry<T, B>(
async fn request_with_body_retry<T>(
&mut self,
endpoint: &str,
method: Method,
body_fn: B,
body_fn: impl Fn() -> Body,
retry_auth: bool) -> Result<T, Error>
where
T: DeserializeOwned,
B: Fn() -> Body
{
use hyper::StatusCode;

View File

@@ -1,6 +1,6 @@
use async_trait::async_trait;
pub use crate::model::{
Conversation, Message, ConversationID, MessageID,
Conversation, Message, ConversationID, MessageID, OutgoingMessage,
};
pub mod auth;
@@ -35,6 +35,12 @@ pub trait APIInterface {
after: Option<MessageID>,
) -> Result<Vec<Message>, Self::Error>;
// (POST) /sendMessage
async fn send_message(
&mut self,
outgoing_message: OutgoingMessage,
) -> Result<Message, Self::Error>;
// (POST) /authenticate
async fn authenticate(&mut self, credentials: Credentials) -> Result<JwtToken, Self::Error>;

View File

@@ -1,6 +1,7 @@
pub mod conversation;
pub mod event;
pub mod message;
pub mod outgoing_message;
pub mod update;
pub use conversation::Conversation;
@@ -9,6 +10,9 @@ pub use conversation::ConversationID;
pub use message::Message;
pub use message::MessageID;
pub use outgoing_message::OutgoingMessage;
pub use outgoing_message::OutgoingMessageBuilder;
pub use update::UpdateItem;
pub use event::Event;

View File

@@ -0,0 +1,56 @@
use serde::Serialize;
use super::conversation::ConversationID;
#[derive(Debug, Clone, Serialize)]
pub struct OutgoingMessage {
#[serde(rename = "body")]
pub text: String,
#[serde(rename = "guid")]
pub conversation_id: ConversationID,
#[serde(rename = "fileTransferGUIDs")]
pub file_transfer_guids: Vec<String>,
}
impl OutgoingMessage {
pub fn builder() -> OutgoingMessageBuilder {
OutgoingMessageBuilder::new()
}
}
#[derive(Default)]
pub struct OutgoingMessageBuilder {
text: Option<String>,
conversation_id: Option<ConversationID>,
file_transfer_guids: Option<Vec<String>>,
}
impl OutgoingMessageBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn text(mut self, text: String) -> Self {
self.text = Some(text);
self
}
pub fn conversation_id(mut self, conversation_id: ConversationID) -> Self {
self.conversation_id = Some(conversation_id);
self
}
pub fn file_transfer_guids(mut self, file_transfer_guids: Vec<String>) -> Self {
self.file_transfer_guids = Some(file_transfer_guids);
self
}
pub fn build(self) -> OutgoingMessage {
OutgoingMessage {
text: self.text.unwrap(),
conversation_id: self.conversation_id.unwrap(),
file_transfer_guids: self.file_transfer_guids.unwrap_or_default(),
}
}
}

View File

@@ -1,10 +1,13 @@
use async_trait::async_trait;
use std::collections::HashMap;
use time::OffsetDateTime;
use uuid::Uuid;
pub use crate::APIInterface;
use crate::{
api::http_client::Credentials,
model::{Conversation, ConversationID, JwtToken, Message, MessageID, UpdateItem, Event},
model::{Conversation, ConversationID, JwtToken, Message, MessageID, UpdateItem, Event, OutgoingMessage},
api::event_socket::EventSocket,
};
@@ -88,6 +91,20 @@ impl APIInterface for TestClient {
Err(TestError::ConversationNotFound)
}
async fn send_message(
&mut self,
outgoing_message: OutgoingMessage,
) -> Result<Message, Self::Error> {
let message = Message::builder()
.guid(Uuid::new_v4().to_string())
.text(outgoing_message.text)
.date(OffsetDateTime::now_utc())
.build();
self.messages.entry(outgoing_message.conversation_id).or_insert(vec![]).push(message.clone());
Ok(message)
}
async fn open_event_socket(&mut self) -> Result<impl EventSocket, Self::Error> {
Ok(TestEventSocket::new())
}