Skip to content

Commit

Permalink
feat: Add save
Browse files Browse the repository at this point in the history
  • Loading branch information
jcs090218 committed Jun 11, 2024
1 parent d1b47eb commit 8cf2449
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 76 deletions.
2 changes: 2 additions & 0 deletions src/chat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
use crate::client::*;

#[derive(Debug)]
pub struct Message {
username: String,
content: String,
Expand All @@ -31,6 +32,7 @@ impl Message {
}
}

#[derive(Debug)]
pub struct Chat {
messages: Vec<Message>, // messages in this file
}
Expand Down
35 changes: 29 additions & 6 deletions src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,22 @@
*/
use crate::chat::*;
use crate::user::*;
use crate::util::*;
use std::collections::HashMap;

#[derive(Debug)]
pub struct File {
path: String, // absolute path
chat: Chat, // messages in this file
view: String, // the file view
path: String, // absolute path
chat: Chat, // messages in this file
view: Option<String>, // the file view
}

impl File {
pub fn new(_path: String) -> Self {
Self {
path: _path,
chat: Chat::new(),
view: String::default(),
view: None,
}
}

Expand All @@ -42,8 +44,29 @@ impl File {
&mut self.chat
}

fn load_file(&mut self) {
if !self.view.is_none() {
return;
}
self.view = Some(read_to_string(&self.path));
}

pub fn update(&mut self, add_or_delete: &String, beg: u64, end: u64, content: &String) {
self.load_file(); // ensure read

match add_or_delete.clone().as_str() {
"add" => {
//self.view.insert(content, beg);
}
"delete" => {}
_ => {
unreachable!()
}
}
}

/// Write the content to file.
pub async fn save(&self) {
// TODO: ..
pub fn save(&self) {
let _ = std::fs::write(&self.path, &self.view.clone().unwrap());
}
}
160 changes: 119 additions & 41 deletions src/handler/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,73 +14,81 @@
* limitations under the License.
*/

/// Return a list of users in the file.
pub mod users {
// Addition and Deletion to the file.
pub mod update {
use crate::channel::*;
use crate::handler::file::*;
use crate::handler::room::*;
use crate::room::*;
use crate::util::*;
use serde_json::Value;
use std::sync::Arc;
use tokio::sync::Mutex;

const METHOD: &str = "file::users";
const METHOD: &str = "file::update";

pub async fn handle(channel: &mut Channel, room: &Arc<Mutex<Room>>, json: &Value) {
let addr = &channel.get_connection().addr;
let room = room.lock().await;
let client = room.get_client(addr).unwrap();
let mut room = room.lock().await;

if !check_entered(channel, &client, METHOD).await {
return;
}
let path = data_str(json, "path").unwrap();
let add_or_delete = data_str(json, "add_or_delete").unwrap();
let beg = data_u64(json, "beg").unwrap();
let end = data_u64(json, "end").unwrap();
let content = data_str(json, "content").unwrap();

let this_user = client.user().unwrap();
let path = to_room_path(&addr, &room, &path);
let file = room.get_file_mut(&path);

// If user is not in the file, ignore it.
if this_user.path.is_none() {
if file.is_none() {
tracing::debug!("Updating an non-existence file: {}", path);
// TODO: Create one?
return;
}

// Prepare data to send.
let mut users = Vec::new();
let file = file.unwrap();

for _client in room.get_clients().iter() {
let user = _client.user();
file.update(&add_or_delete, beg, end, &content);
}
}

if user.is_none() {
continue;
}
/// Save file.
pub mod save {
use crate::channel::*;
use crate::handler::file::*;
use crate::handler::room::*;
use crate::room::*;
use crate::util::*;
use serde_json::Value;
use std::sync::Arc;
use tokio::sync::Mutex;

let user = user.unwrap();
const METHOD: &str = "file::save";

// Ignore the sender client.
if this_user == user {
continue;
}

// Ignore when user not visiting any project files.
if user.path.is_none() {
continue;
}
pub async fn handle(channel: &mut Channel, room: &Arc<Mutex<Room>>, json: &Value) {
let addr = &channel.get_connection().addr;
let mut room = room.lock().await;

// Ignore if not in the same file.
if client.user_relative_path() != _client.user_relative_path() {
continue;
}
let path = data_str(json, "path").unwrap();
let path = to_room_path(&addr, &room, &path);
let file = room.get_file_mut(&path);

users.push(user.clone());
if file.is_none() {
tracing::debug!("Updating an non-existence file: {}", path);
// TODO: Create one?
return;
}

let users = serde_json::to_string(&users).unwrap();
let file = file.unwrap();
file.save();

channel
.send_json(&serde_json::json!({
"method": METHOD,
"clients": users,
"status": "success",
}))
.await;
let relative_path = no_room_path(&room, &path);

room.broadcast_json(&serde_json::json!({
"method": METHOD,
"file": relative_path,
"status": "success",
}));
}
}

Expand Down Expand Up @@ -125,6 +133,76 @@ pub mod sync {
}
}

/// Return a list of users in the file.
pub mod users {
use crate::channel::*;
use crate::handler::room::*;
use crate::room::*;
use crate::util::*;
use serde_json::Value;
use std::sync::Arc;
use tokio::sync::Mutex;

const METHOD: &str = "file::users";

pub async fn handle(channel: &mut Channel, room: &Arc<Mutex<Room>>, json: &Value) {
let addr = &channel.get_connection().addr;
let room = room.lock().await;
let client = room.get_client(addr).unwrap();

if !check_entered(channel, &client, METHOD).await {
return;
}

let this_user = client.user().unwrap();

// If user is not in the file, ignore it.
if this_user.path.is_none() {
return;
}

// Prepare data to send.
let mut users = Vec::new();

for _client in room.get_clients().iter() {
let user = _client.user();

if user.is_none() {
continue;
}

let user = user.unwrap();

// Ignore the sender client.
if this_user == user {
continue;
}

// Ignore when user not visiting any project files.
if user.path.is_none() {
continue;
}

// Ignore if not in the same file.
if client.user_relative_path() != _client.user_relative_path() {
continue;
}

users.push(user.clone());
}

let users = serde_json::to_string(&users).unwrap();

channel
.send_json(&serde_json::json!({
"method": METHOD,
"clients": users,
"status": "success",
}))
.await;
}
}

/// Say
pub mod say {
use crate::channel::*;
Expand Down
5 changes: 3 additions & 2 deletions src/handler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ use crate::room::*;
use serde_json::Value;
use std::sync::Arc;
use tokio::sync::Mutex;

pub async fn handle(channel: &mut Channel, room: &Arc<Mutex<Room>>, json: &str) {
let v = serde_json::from_str(json);
let val: Value = v.unwrap();
Expand All @@ -40,9 +39,11 @@ pub async fn handle(channel: &mut Channel, room: &Arc<Mutex<Room>>, json: &str)
"room::users" => room::users::handle(channel, room, &val).await,
"room::sync" => room::sync::handle(channel, room, &val).await,
"room::update_client" => room::update_client::handle(channel, room, &val).await,
"file::update" => file::update::handle(channel, room, &val).await,
"file::save" => file::save::handle(channel, room, &val).await,
"file::sync" => file::sync::handle(channel, room, &val).await,
"file::users" => file::users::handle(channel, room, &val).await,
"file::say" => file::say::handle(channel, room, &val).await,
"file::sync" => file::sync::handle(channel, room, &val).await,
_ => {
tracing::error!("Unkown method request: {:?}", method);
}
Expand Down
28 changes: 3 additions & 25 deletions src/handler/room.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@
use crate::channel::*;
use crate::client::*;
use crate::room::*;
use serde_json::Value;
use std::fs;
use std::net::SocketAddr;
use std::sync::Arc;
use tokio::sync::Mutex;

Expand Down Expand Up @@ -87,20 +84,6 @@ pub async fn check_admin(channel: &mut Channel, client: &Client, method: &str) -
return false;
}

/// Convert path's absolute project path to this room path.
///
/// # Arguments
///
/// * `addr` - Socket address used to get the client's project path.
/// * `room` - Used to get client and room path.
/// * `path` - Path we want to convert.
pub fn to_room_path(addr: &SocketAddr, room: &Room, path: &str) -> String {
let server_path = room.get_path().clone();
let client = room.get_client(addr).unwrap();
let project_path = client.get_path();
path.replace(project_path, &server_path)
}

/// Enter room
pub mod enter {
use crate::channel::*;
Expand Down Expand Up @@ -202,10 +185,9 @@ pub mod exit {
pub mod kick {
use crate::channel::*;
use crate::handler::room::*;
use crate::room::*;
use crate::util::*;
use serde_json::Value;
use std::sync::{Arc, MutexGuard};
use std::sync::Arc;
use tokio::sync::Mutex;

const METHOD: &str = "room::kick";
Expand Down Expand Up @@ -259,10 +241,9 @@ pub mod kick {
pub mod broadcast {
use crate::channel::*;
use crate::handler::room::*;
use crate::room::*;
use crate::util::*;
use serde_json::Value;
use std::sync::{Arc, MutexGuard};
use std::sync::Arc;
use tokio::sync::Mutex;

const METHOD: &str = "room::broadcast";
Expand Down Expand Up @@ -293,7 +274,6 @@ pub mod broadcast {
pub mod update_client {
use crate::channel::*;
use crate::handler::room::*;
use crate::room::*;
use crate::util::*;
use serde_json::Value;
use std::sync::Arc;
Expand Down Expand Up @@ -329,7 +309,6 @@ pub mod update_client {
pub mod users {
use crate::channel::*;
use crate::handler::room::*;
use crate::room::*;
use serde_json::Value;
use std::sync::Arc;
use tokio::sync::Mutex;
Expand Down Expand Up @@ -369,7 +348,6 @@ pub mod users {
pub mod sync {
use crate::channel::*;
use crate::handler::room::*;
use crate::room::*;
use crate::util::*;
use serde_json::Value;
use std::sync::Arc;
Expand All @@ -389,7 +367,7 @@ pub mod sync {
let project_path = data_str(json, "path").unwrap();

let room_path = room.get_path().clone();
let files = room.get_files();
let files = room.get_path_files();

for file in files.into_iter() {
let abs_path = file;
Expand Down
4 changes: 2 additions & 2 deletions src/room.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,12 @@ impl Room {
/// # Arguments
///
/// * `path` - The file path.
pub fn get_file(&mut self, path: &String) -> Option<&mut File> {
pub fn get_file_mut(&mut self, path: &String) -> Option<&mut File> {
self.files.get_mut(path)
}

/// Return a list of files need to be sync.
pub fn get_files(&self) -> Vec<&String> {
pub fn get_path_files(&self) -> Vec<&String> {
self.files.keys().clone().collect::<Vec<&String>>()
}

Expand Down
Loading

0 comments on commit 8cf2449

Please sign in to comment.