Skip to content
This repository was archived by the owner on Feb 14, 2025. It is now read-only.

Commit 268925a

Browse files
committed
docs: 📝 exposed urls
1 parent fb951c4 commit 268925a

File tree

6 files changed

+196
-41
lines changed

6 files changed

+196
-41
lines changed

.github/workflows/rust.yml

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: Rust Build && Test
2+
3+
on:
4+
push:
5+
branches: [ "main" ]
6+
pull_request:
7+
branches: [ "main" ]
8+
9+
env:
10+
CARGO_TERM_COLOR: always
11+
12+
jobs:
13+
build:
14+
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- uses: actions/checkout@v4
19+
- name: Build
20+
run: cargo build --verbose
21+
- name: Run tests
22+
run: cargo test --verbose

README.md

+22
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,24 @@
11
# acapair_chat_api
22
Acapair Chat API
3+
4+
[![Rust Build && Test](https://github.com/Acapair/acapair_chat_api/actions/workflows/rust.yml/badge.svg)](https://github.com/Acapair/acapair_chat_api/actions/workflows/rust.yml)
5+
6+
7+
## Exposed URLs
8+
> ':' means they are variable.
9+
10+
Alive Ping(get): "/"
11+
12+
---
13+
14+
Send Message(post): "/send"
15+
16+
| Body Fields | Example Values |
17+
| -------- | ------- |
18+
| "room_id" | "Tahinli's Room -1" |
19+
| "username" | "Tahinli" |
20+
| "message" | "Hi!" |
21+
22+
---
23+
24+
Receive Message(get): "/receive/:room_id"

src/lib.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use tokio::sync::Mutex;
66

77
pub mod chat;
88
pub mod routing;
9+
pub mod routing_operations;
910
pub mod test;
1011
pub mod utils;
1112

@@ -24,7 +25,7 @@ pub struct AppState {
2425
}
2526

2627
impl AppState {
27-
pub async fn is_chat_exists(&mut self, room_id: &String) -> Option<usize> {
28+
pub async fn is_chat_exists(&self, room_id: &String) -> Option<usize> {
2829
let chats = self.chats.lock().await;
2930
for i in 0..chats.len() {
3031
if chats[i].room_id == *room_id {
@@ -52,10 +53,6 @@ impl AppState {
5253
}
5354
}
5455
}
55-
// if chats[chat_index].last_interaction < current - chat_cleaning_timeout as u64 {
56-
// chats.remove(chat_index);
57-
// return;
58-
// }
5956
}
6057
}
6158
}

src/routing.rs

+5-36
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@ use axum::{
88
use serde::Deserialize;
99
use tower_http::cors::CorsLayer;
1010

11-
use crate::{
12-
chat::{Chat, Message},
13-
AppState,
14-
};
11+
use crate::{routing_operations, AppState};
1512

1613
#[derive(Debug, Deserialize)]
1714
struct ReceivedMessage {
@@ -37,46 +34,18 @@ async fn alive() -> impl IntoResponse {
3734
}
3835

3936
async fn receive_message(
40-
State(mut state): State<AppState>,
37+
State(state): State<AppState>,
4138
Json(received_message): Json<ReceivedMessage>,
4239
) {
4340
let sender = received_message.username;
4441
let data = received_message.message;
4542
let room_id = received_message.room_id;
46-
let message = Message::new(sender, data);
47-
match state.is_chat_exists(&room_id).await {
48-
Some(index) => {
49-
let mut chats = state.chats.lock().await;
50-
chats[index].add_message(message, state.max_message_counter);
51-
}
52-
None => {
53-
let mut new_chat = Chat::new(room_id);
54-
new_chat.add_message(message, state.max_message_counter);
55-
let mut chats = state.chats.lock().await;
56-
let room_id = new_chat.room_id.clone();
57-
chats.push(new_chat);
58-
drop(chats);
59-
tokio::spawn(AppState::chat_destroyer(
60-
state.chats.clone(),
61-
room_id,
62-
state.chat_cleaning_timeout,
63-
));
64-
}
65-
}
43+
routing_operations::receive_message(sender, data, room_id, &state).await;
6644
}
6745

6846
async fn send_message(
6947
Path(room_id): Path<String>,
70-
State(mut state): State<AppState>,
48+
State(state): State<AppState>,
7149
) -> impl IntoResponse {
72-
match state.is_chat_exists(&room_id).await {
73-
Some(index) => {
74-
let chats = state.chats.lock().await;
75-
(
76-
StatusCode::OK,
77-
serde_json::to_string(&chats[index]).unwrap(),
78-
)
79-
}
80-
None => (StatusCode::BAD_REQUEST, serde_json::to_string("").unwrap()),
81-
}
50+
routing_operations::send_message(room_id, state).await
8251
}

src/routing_operations.rs

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use axum::http::StatusCode;
2+
3+
use crate::{
4+
chat::{Chat, Message},
5+
AppState,
6+
};
7+
8+
pub async fn receive_message(
9+
sender: impl ToString,
10+
data: impl ToString,
11+
room_id: impl ToString,
12+
state: &AppState,
13+
) {
14+
let message = Message::new(sender.to_string(), data.to_string());
15+
match state.is_chat_exists(&room_id.to_string()).await {
16+
Some(index) => {
17+
let mut chats = state.chats.lock().await;
18+
chats[index].add_message(message, state.max_message_counter);
19+
}
20+
None => {
21+
let mut new_chat = Chat::new(room_id.to_string());
22+
new_chat.add_message(message, state.max_message_counter);
23+
let mut chats = state.chats.lock().await;
24+
let room_id = new_chat.room_id.clone();
25+
chats.push(new_chat);
26+
drop(chats);
27+
tokio::spawn(AppState::chat_destroyer(
28+
state.chats.clone(),
29+
room_id,
30+
state.chat_cleaning_timeout,
31+
));
32+
}
33+
}
34+
}
35+
36+
pub async fn send_message(
37+
room_id: impl ToString,
38+
state: AppState,
39+
) -> (axum::http::StatusCode, std::string::String) {
40+
match state.is_chat_exists(&room_id.to_string()).await {
41+
Some(index) => {
42+
let chats = state.chats.lock().await;
43+
(
44+
StatusCode::OK,
45+
serde_json::to_string(&chats[index]).unwrap(),
46+
)
47+
}
48+
None => (StatusCode::BAD_REQUEST, serde_json::to_string("").unwrap()),
49+
}
50+
}

src/test.rs

+95
Original file line numberDiff line numberDiff line change
@@ -1 +1,96 @@
1+
#[cfg(test)]
2+
use crate::{routing_operations::receive_message, AppState};
3+
#[cfg(test)]
4+
use std::sync::Arc;
5+
#[cfg(test)]
6+
use std::time::Duration;
7+
#[cfg(test)]
8+
use tokio::sync::Mutex;
19

10+
#[tokio::test]
11+
async fn new_message_no_chat() {
12+
let state = AppState {
13+
chats: Arc::new(Mutex::new(vec![])),
14+
max_message_counter: 5,
15+
chat_cleaning_timeout: 10,
16+
};
17+
receive_message("Tahinli", "Hi", "Tahinli-Chat", &state).await;
18+
let chats = state.chats.lock().await;
19+
assert_eq!(chats.len(), 1);
20+
assert_eq!(chats[0].messages.len(), 1);
21+
}
22+
23+
#[tokio::test]
24+
async fn new_message_with_chat() {
25+
let state = AppState {
26+
chats: Arc::new(Mutex::new(vec![])),
27+
max_message_counter: 5,
28+
chat_cleaning_timeout: 10,
29+
};
30+
receive_message("Tahinli", "Hi", "Tahinli-Chat", &state).await;
31+
let chats = state.chats.lock().await;
32+
assert_eq!(chats.len(), 1);
33+
assert_eq!(chats[0].messages.len(), 1);
34+
drop(chats);
35+
36+
receive_message("Tahinli", "Hi Again", "Tahinli-Chat", &state).await;
37+
let chats = state.chats.lock().await;
38+
assert_eq!(chats.len(), 1);
39+
assert_eq!(chats[0].messages.len(), 2);
40+
}
41+
42+
#[tokio::test]
43+
async fn chat_auto_deletion_with_timeout() {
44+
let state = AppState {
45+
chats: Arc::new(Mutex::new(vec![])),
46+
max_message_counter: 5,
47+
chat_cleaning_timeout: 1,
48+
};
49+
receive_message("Tahinli", "Hi", "Tahinli-Chat", &state).await;
50+
let chats = state.chats.lock().await;
51+
assert_eq!(chats.len(), 1);
52+
assert_eq!(chats[0].messages.len(), 1);
53+
drop(chats);
54+
55+
tokio::time::sleep(Duration::from_secs(2)).await;
56+
let chats = state.chats.lock().await;
57+
assert_eq!(chats.len(), 0);
58+
}
59+
60+
#[tokio::test]
61+
async fn message_auto_deletion_with_counter() {
62+
let state = AppState {
63+
chats: Arc::new(Mutex::new(vec![])),
64+
max_message_counter: 1,
65+
chat_cleaning_timeout: 10,
66+
};
67+
receive_message("Tahinli", "Hi", "Tahinli-Chat", &state).await;
68+
let chats = state.chats.lock().await;
69+
assert_eq!(chats.len(), 1);
70+
assert_eq!(chats[0].messages.len(), 1);
71+
drop(chats);
72+
73+
receive_message("Tahinli", "Hi", "Tahinli-Chat", &state).await;
74+
let chats = state.chats.lock().await;
75+
assert_eq!(chats.len(), 1);
76+
assert_eq!(chats[0].messages.len(), 1);
77+
}
78+
79+
#[tokio::test]
80+
async fn create_multiple_chats() {
81+
let state = AppState {
82+
chats: Arc::new(Mutex::new(vec![])),
83+
max_message_counter: 1,
84+
chat_cleaning_timeout: 10,
85+
};
86+
receive_message("Tahinli", "Hi", "Tahinli-Chat-1", &state).await;
87+
let chats = state.chats.lock().await;
88+
assert_eq!(chats.len(), 1);
89+
assert_eq!(chats[0].messages.len(), 1);
90+
drop(chats);
91+
92+
receive_message("Tahinli", "Hi", "Tahinli-Chat-2", &state).await;
93+
let chats = state.chats.lock().await;
94+
assert_eq!(chats.len(), 2);
95+
assert_eq!(chats[1].messages.len(), 1);
96+
}

0 commit comments

Comments
 (0)