more refactor on backend
This commit is contained in:
1 parent
941afa2485
commit
7f7936d37f
20 files changed
+1603
-1527
No files matched your search
+164
@@ -0,0 +1,164 @@
|
||||
use crate::model;
|
||||
use crate::state;
|
||||
use axum::extract::ws::Message;
|
||||
use rand::distributions::Alphanumeric;
|
||||
use rand::{Rng, thread_rng};
|
||||
use sqlx::{Row, SqlitePool};
|
||||
use std::io::Cursor;
|
||||
|
||||
// Utility functions
|
||||
pub fn generate_token() -> String {
|
||||
thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(32)
|
||||
.map(char::from)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub async fn verify_token(pool: &SqlitePool, token: &str) -> Result<Option<String>, sqlx::Error> {
|
||||
let result = sqlx::query(
|
||||
"SELECT username FROM sessions WHERE token = ? AND expires_at > datetime('now')",
|
||||
)
|
||||
.bind(token)
|
||||
.fetch_optional(pool)
|
||||
.await?;
|
||||
|
||||
Ok(result.map(|row| row.get("username")))
|
||||
}
|
||||
|
||||
pub async fn mark_messages_as_read(
|
||||
pool: &SqlitePool,
|
||||
from_user: &str,
|
||||
to_user: &str,
|
||||
) -> Result<(), sqlx::Error> {
|
||||
let result = sqlx::query(
|
||||
"UPDATE messages SET read = TRUE WHERE from_user = ? AND to_user = ? AND read = FALSE AND deleted_for_everyone = FALSE"
|
||||
)
|
||||
.bind(from_user)
|
||||
.bind(to_user)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
println!(
|
||||
"✅ Marked {} messages as read from {} to {}",
|
||||
result.rows_affected(),
|
||||
from_user,
|
||||
to_user
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Process and resize avatar
|
||||
pub async fn process_avatar(data: &[u8]) -> Result<Vec<u8>, String> {
|
||||
// Load image
|
||||
let img = match image::load_from_memory(data) {
|
||||
Ok(img) => img,
|
||||
Err(_) => return Err("Invalid image format".to_string()),
|
||||
};
|
||||
|
||||
// Resize image to 150x150 pixels
|
||||
let resized = img.resize_to_fill(150, 150, image::imageops::FilterType::Lanczos3);
|
||||
|
||||
// Convert to JPEG
|
||||
let mut jpeg_data = Vec::new();
|
||||
match resized.write_to(&mut Cursor::new(&mut jpeg_data), image::ImageFormat::Jpeg) {
|
||||
Ok(_) => Ok(jpeg_data),
|
||||
Err(_) => Err("Error processing image".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_message_history(
|
||||
pool: &SqlitePool,
|
||||
username: &str,
|
||||
other_user: &str,
|
||||
) -> Result<Vec<model::ChatMessage>, sqlx::Error> {
|
||||
// Если указан конкретный собеседник, помечаем сообщения как прочитанные
|
||||
if !other_user.is_empty() {
|
||||
mark_messages_as_read(pool, other_user, username).await?;
|
||||
}
|
||||
|
||||
let query = if other_user.is_empty() {
|
||||
// Получаем все сообщения пользователя (исключая удаленные)
|
||||
r#"
|
||||
SELECT id, from_user, to_user, content, timestamp, message_type
|
||||
FROM messages
|
||||
WHERE (from_user = ? OR to_user = ?)
|
||||
AND deleted_for_everyone = FALSE
|
||||
AND ((from_user = ? AND deleted_for_sender = FALSE) OR (to_user = ? AND deleted_for_receiver = FALSE))
|
||||
ORDER BY timestamp
|
||||
"#
|
||||
} else {
|
||||
// Получаем сообщения только с конкретным пользователем (исключая удаленные)
|
||||
r#"
|
||||
SELECT id, from_user, to_user, content, timestamp, message_type
|
||||
FROM messages
|
||||
WHERE ((from_user = ? AND to_user = ?) OR (from_user = ? AND to_user = ?))
|
||||
AND deleted_for_everyone = FALSE
|
||||
AND ((from_user = ? AND deleted_for_sender = FALSE) OR (to_user = ? AND deleted_for_receiver = FALSE))
|
||||
ORDER BY timestamp
|
||||
"#
|
||||
};
|
||||
|
||||
let rows = if other_user.is_empty() {
|
||||
sqlx::query(query)
|
||||
.bind(username)
|
||||
.bind(username)
|
||||
.bind(username)
|
||||
.bind(username)
|
||||
.fetch_all(pool)
|
||||
.await?
|
||||
} else {
|
||||
sqlx::query(query)
|
||||
.bind(username)
|
||||
.bind(other_user)
|
||||
.bind(other_user)
|
||||
.bind(username)
|
||||
.bind(username)
|
||||
.bind(username)
|
||||
.fetch_all(pool)
|
||||
.await?
|
||||
};
|
||||
|
||||
let mut messages = Vec::new();
|
||||
for row in rows {
|
||||
let message = model::ChatMessage {
|
||||
id: row.get("id"),
|
||||
from_user: row.get("from_user"),
|
||||
to_user: row.get("to_user"),
|
||||
content: row.get("content"),
|
||||
timestamp: row.get("timestamp"),
|
||||
message_type: row.get("message_type"),
|
||||
};
|
||||
messages.push(message);
|
||||
}
|
||||
|
||||
Ok(messages)
|
||||
}
|
||||
|
||||
pub async fn broadcast_user_list(users: &state::UserMap) {
|
||||
let user_list: Vec<String> = users.read().await.keys().cloned().collect();
|
||||
let user_list_msg = serde_json::json!({
|
||||
"type": "user_list",
|
||||
"users": user_list
|
||||
});
|
||||
|
||||
for tx in users.read().await.values() {
|
||||
let _ = tx.send(Message::Text(user_list_msg.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn save_message(pool: &SqlitePool, msg: &model::ChatMessage) -> Result<(), sqlx::Error> {
|
||||
sqlx::query(
|
||||
"INSERT OR REPLACE INTO messages (id, from_user, to_user, content, timestamp, message_type) VALUES (?, ?, ?, ?, ?, ?)",
|
||||
)
|
||||
.bind(&msg.id)
|
||||
.bind(&msg.from_user)
|
||||
.bind(&msg.to_user)
|
||||
.bind(&msg.content)
|
||||
.bind(msg.timestamp)
|
||||
.bind(&msg.message_type)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in new issue
Block a user