diff --git a/README.md b/README.md index ce8672e66..976d2e55c 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ We have a twitter alternative (mastodon), a facebook alternative (friendica), so - [Sticky Sidebar](https://stackoverflow.com/questions/38382043/how-to-use-css-position-sticky-to-keep-a-sidebar-visible-with-bootstrap-4/49111934) - [RXJS websocket](https://stackoverflow.com/questions/44060315/reconnecting-a-websocket-in-angular-and-rxjs/44067972#44067972) - [Rust JWT](https://github.com/Keats/jsonwebtoken) +- [Hierarchical tree building javascript](https://stackoverflow.com/a/40732240/1655478) ## TODOs - Endpoints diff --git a/server/src/bin/main.rs b/server/src/bin/main.rs index 1d674cbc6..08663f563 100644 --- a/server/src/bin/main.rs +++ b/server/src/bin/main.rs @@ -83,7 +83,6 @@ impl Handler for WSSession { fn handle(&mut self, msg: WSMessage, ctx: &mut Self::Context) { println!("id: {} msg: {}", self.id, msg.0); ctx.text(msg.0); - ctx.text("NO"); } } @@ -122,7 +121,7 @@ impl StreamHandler for WSSession { // _ => ctx.stop(), fut::ok(()) }) - .wait(ctx); + .wait(ctx); // we check for /sss type of messages // if m.starts_with('/') { diff --git a/server/src/websocket_server/server.rs b/server/src/websocket_server/server.rs index 224843978..d257f4c00 100644 --- a/server/src/websocket_server/server.rs +++ b/server/src/websocket_server/server.rs @@ -190,15 +190,14 @@ pub struct CreateCommentResponse { /// session. implementation is super primitive pub struct ChatServer { sessions: HashMap>, // A map from generated random ID to session addr - rooms: HashMap>, // A map from room name to set of connectionIDs + rooms: HashMap>, // A map from room / post name to set of connectionIDs rng: ThreadRng, } impl Default for ChatServer { fn default() -> ChatServer { // default room - let mut rooms = HashMap::new(); - rooms.insert("Main".to_owned(), HashSet::new()); + let rooms = HashMap::new(); ChatServer { sessions: HashMap::new(), @@ -210,8 +209,8 @@ impl Default for ChatServer { impl ChatServer { /// Send message to all users in the room - fn send_room_message(&self, room: &str, message: &str, skip_id: usize) { - if let Some(sessions) = self.rooms.get(room) { + fn send_room_message(&self, room: i32, message: &str, skip_id: usize) { + if let Some(sessions) = self.rooms.get(&room) { for id in sessions { if *id != skip_id { if let Some(addr) = self.sessions.get(id) { @@ -250,14 +249,14 @@ impl Handler for ChatServer { println!("Someone joined"); // notify all users in same room - self.send_room_message(&"Main".to_owned(), "Someone joined", 0); + // self.send_room_message(&"Main".to_owned(), "Someone joined", 0); // register session with random id let id = self.rng.gen::(); self.sessions.insert(id, msg.addr); // auto join session to Main room - self.rooms.get_mut(&"Main".to_owned()).unwrap().insert(id); + // self.rooms.get_mut(&"Main".to_owned()).unwrap().insert(id); // send id back id @@ -271,32 +270,32 @@ impl Handler for ChatServer { fn handle(&mut self, msg: Disconnect, _: &mut Context) { println!("Someone disconnected"); - let mut rooms: Vec = Vec::new(); + let mut rooms: Vec = Vec::new(); // remove address if self.sessions.remove(&msg.id).is_some() { // remove session from all rooms - for (name, sessions) in &mut self.rooms { + for (id, sessions) in &mut self.rooms { if sessions.remove(&msg.id) { - rooms.push(name.to_owned()); + // rooms.push(*id); } } } // send message to other users - for room in rooms { - self.send_room_message(&room, "Someone disconnected", 0); - } + // for room in rooms { + // self.send_room_message(room, "Someone disconnected", 0); + // } } } /// Handler for Message message. -impl Handler for ChatServer { - type Result = (); +// impl Handler for ChatServer { +// type Result = (); - fn handle(&mut self, msg: ClientMessage, _: &mut Context) { - self.send_room_message(&msg.room, msg.msg.as_str(), msg.id); - } -} +// fn handle(&mut self, msg: ClientMessage, _: &mut Context) { +// self.send_room_message(&msg.room, msg.msg.as_str(), msg.id); +// } +// } /// Handler for Message message. impl Handler for ChatServer { @@ -314,35 +313,35 @@ impl Handler for ChatServer { let res: String = match user_operation { UserOperation::Login => { let login: Login = serde_json::from_str(&data.to_string()).unwrap(); - login.perform() + login.perform(self, msg.id) }, UserOperation::Register => { let register: Register = serde_json::from_str(&data.to_string()).unwrap(); - register.perform() + register.perform(self, msg.id) }, UserOperation::CreateCommunity => { let create_community: CreateCommunity = serde_json::from_str(&data.to_string()).unwrap(); - create_community.perform() + create_community.perform(self, msg.id) }, UserOperation::ListCommunities => { let list_communities: ListCommunities = ListCommunities; - list_communities.perform() + list_communities.perform(self, msg.id) }, UserOperation::CreatePost => { let create_post: CreatePost = serde_json::from_str(&data.to_string()).unwrap(); - create_post.perform() + create_post.perform(self, msg.id) }, UserOperation::GetPost => { let get_post: GetPost = serde_json::from_str(&data.to_string()).unwrap(); - get_post.perform() + get_post.perform(self, msg.id) }, UserOperation::GetCommunity => { let get_community: GetCommunity = serde_json::from_str(&data.to_string()).unwrap(); - get_community.perform() + get_community.perform(self, msg.id) }, UserOperation::CreateComment => { let create_comment: CreateComment = serde_json::from_str(&data.to_string()).unwrap(); - create_comment.perform() + create_comment.perform(self, msg.id) }, _ => { let e = ErrorMessage { @@ -351,7 +350,6 @@ impl Handler for ChatServer { }; serde_json::to_string(&e).unwrap() } - // _ => "no".to_string() }; MessageResult(res) @@ -360,7 +358,7 @@ impl Handler for ChatServer { pub trait Perform { - fn perform(&self) -> String; + fn perform(&self, chat: &mut ChatServer, addr: usize) -> String; fn op_type(&self) -> UserOperation; fn error(&self, error_msg: &str) -> String { serde_json::to_string( @@ -377,7 +375,7 @@ impl Perform for Login { fn op_type(&self) -> UserOperation { UserOperation::Login } - fn perform(&self) -> String { + fn perform(&self, chat: &mut ChatServer, addr: usize) -> String { let conn = establish_connection(); @@ -409,7 +407,7 @@ impl Perform for Register { fn op_type(&self) -> UserOperation { UserOperation::Register } - fn perform(&self) -> String { + fn perform(&self, chat: &mut ChatServer, addr: usize) -> String { let conn = establish_connection(); @@ -452,7 +450,7 @@ impl Perform for CreateCommunity { UserOperation::CreateCommunity } - fn perform(&self) -> String { + fn perform(&self, chat: &mut ChatServer, addr: usize) -> String { let conn = establish_connection(); @@ -505,7 +503,7 @@ impl Perform for ListCommunities { UserOperation::ListCommunities } - fn perform(&self) -> String { + fn perform(&self, chat: &mut ChatServer, addr: usize) -> String { let conn = establish_connection(); @@ -527,7 +525,7 @@ impl Perform for CreatePost { UserOperation::CreatePost } - fn perform(&self) -> String { + fn perform(&self, chat: &mut ChatServer, addr: usize) -> String { let conn = establish_connection(); @@ -574,7 +572,7 @@ impl Perform for GetPost { UserOperation::GetPost } - fn perform(&self) -> String { + fn perform(&self, chat: &mut ChatServer, addr: usize) -> String { let conn = establish_connection(); @@ -585,8 +583,38 @@ impl Perform for GetPost { } }; + + // let mut rooms = Vec::new(); + + // remove session from all rooms + for (n, sessions) in &mut chat.rooms { + // if sessions.remove(&addr) { + // // rooms.push(*n); + // } + sessions.remove(&addr); + } + // // send message to other users + // for room in rooms { + // self.send_room_message(&room, "Someone disconnected", 0); + // } + + if chat.rooms.get_mut(&self.id).is_none() { + chat.rooms.insert(self.id, HashSet::new()); + } + + // TODO send a Joined response + + + + // chat.send_room_message(addr,) + // self.send_room_message(&name, "Someone connected", id); + chat.rooms.get_mut(&self.id).unwrap().insert(addr); + let comments = Comment::from_post(&conn, &post).unwrap(); + println!("{:?}", chat.rooms.keys()); + println!("{:?}", chat.rooms.get(&5i32).unwrap()); + // Return the jwt serde_json::to_string( &GetPostResponse { @@ -604,7 +632,7 @@ impl Perform for GetCommunity { UserOperation::GetCommunity } - fn perform(&self) -> String { + fn perform(&self, chat: &mut ChatServer, addr: usize) -> String { let conn = establish_connection(); @@ -631,7 +659,7 @@ impl Perform for CreateComment { UserOperation::CreateComment } - fn perform(&self) -> String { + fn perform(&self, chat: &mut ChatServer, addr: usize) -> String { let conn = establish_connection(); @@ -660,13 +688,20 @@ impl Perform for CreateComment { } }; - serde_json::to_string( + let comment_out = serde_json::to_string( &CreateCommentResponse { op: self.op_type().to_string(), comment: inserted_comment } ) - .unwrap() + .unwrap(); + + chat.send_room_message(self.post_id, &comment_out, addr); + + println!("{:?}", chat.rooms.keys()); + println!("{:?}", chat.rooms.get(&5i32).unwrap()); + + comment_out } } diff --git a/ui/src/components/create-community.tsx b/ui/src/components/create-community.tsx index 0a0edae6a..7e56fcdab 100644 --- a/ui/src/components/create-community.tsx +++ b/ui/src/components/create-community.tsx @@ -78,7 +78,6 @@ export class CreateCommunity extends Component { handleCommunityNameChange(i: CreateCommunity, event) { i.state.communityForm.name = event.target.value; - i.setState(i.state); } parseMessage(msg: any) { diff --git a/ui/src/components/create-post.tsx b/ui/src/components/create-post.tsx index 9ddf8c97f..3d5dceda3 100644 --- a/ui/src/components/create-post.tsx +++ b/ui/src/components/create-post.tsx @@ -105,22 +105,18 @@ export class CreatePost extends Component { handlePostUrlChange(i: CreatePost, event) { i.state.postForm.url = event.target.value; - i.setState(i.state); } handlePostNameChange(i: CreatePost, event) { i.state.postForm.name = event.target.value; - i.setState(i.state); } handlePostBodyChange(i: CreatePost, event) { i.state.postForm.body = event.target.value; - i.setState(i.state); } handlePostCommunityChange(i: CreatePost, event) { i.state.postForm.community_id = Number(event.target.value); - i.setState(i.state); } parseMessage(msg: any) { @@ -132,6 +128,7 @@ export class CreatePost extends Component { } else if (op == UserOperation.ListCommunities) { let res: ListCommunitiesResponse = msg; this.state.communities = res.communities; + this.state.postForm.community_id = res.communities[0].id; // TODO set it to the default community this.setState(this.state); } else if (op == UserOperation.CreatePost) { let res: PostResponse = msg; diff --git a/ui/src/components/post.tsx b/ui/src/components/post.tsx index 8d84f27ac..193da3de0 100644 --- a/ui/src/components/post.tsx +++ b/ui/src/components/post.tsx @@ -1,13 +1,18 @@ import { Component, linkEvent } from 'inferno'; import { Subscription } from "rxjs"; import { retryWhen, delay, take } from 'rxjs/operators'; -import { UserOperation, Community, Post as PostI, PostResponse, Comment, CommentForm } from '../interfaces'; +import { UserOperation, Community, Post as PostI, PostResponse, Comment, CommentForm as CommentFormI, CommentResponse } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { msgOp } from '../utils'; +interface CommentNodeI { + comment: Comment; + children?: Array; + showReply?: boolean; +}; + interface State { post: PostI; - commentForm: CommentForm; comments: Array; } @@ -22,21 +27,15 @@ export class Post extends Component { id: null, published: null, }, - commentForm: { - auth: null, - content: null, - post_id: null - }, comments: [] } constructor(props, context) { super(props, context); - let postId = Number(this.props.match.params.id); - this.state = this.emptyState; - this.state.commentForm.post_id = postId; + + this.state.post.id = Number(this.props.match.params.id); this.subscription = WebSocketService.Instance.subject .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) @@ -46,7 +45,7 @@ export class Post extends Component { () => console.log('complete') ); - WebSocketService.Instance.getPost(postId); + WebSocketService.Instance.getPost(this.state.post.id); } componentWillUnmount() { @@ -57,59 +56,88 @@ export class Post extends Component { return (
-
- {this.state.post.name} - {this.commentForm()} - {this.comments()} +
+ {this.postHeader()} + + {this.commentsTree()} +
+
+ {this.newComments()} +
+
+ {this.sidebar()}
) } - comments() { + postHeader() { + let title = this.state.post.url + ?
{this.state.post.name}
+ :
{this.state.post.name}
; return (
-

Comments

+ {title} + via {this.state.post.attributed_to} X hours ago + {this.state.post.body} +
+ ) + } + + newComments() { + return ( +
+

New Comments

{this.state.comments.map(comment => -
{comment.content}
+ )}
) } - - - commentForm() { - return ( -
-
-

Create Comment

-
- -
-