//! `ChatServer` is an actor. It maintains list of connection client session.
//! And manages available rooms. Peers send messages to other peers in same
//! room through `ChatServer`.
use actix::prelude::*;
use rand::{rngs::ThreadRng, Rng};
use std::collections::{HashMap, HashSet};
use serde::{Deserialize, Serialize};
use serde_json::{Result, Value};
use bcrypt::{verify};
use std::str::FromStr;
use std::{thread, time};
use {Crud, Joinable, Likeable, establish_connection};
use actions::community::*;
use actions::user::*;
use actions::post::*;
use actions::comment::*;
#[derive(EnumString,ToString,Debug)]
pub enum UserOperation {
Login, Register, Logout, CreateCommunity, ListCommunities, CreatePost, GetPost, GetCommunity, CreateComment, CreateCommentLike, Join, Edit, Reply, Vote, Delete, NextPage, Sticky
}
#[derive(EnumString,ToString,Debug)]
pub enum MessageToUser {
Comments, Users, Ping, Pong, Error
}
#[derive(Serialize, Deserialize)]
pub struct ErrorMessage {
op: String,
error: String
}
/// Chat server sends this messages to session
#[derive(Message)]
pub struct WSMessage(pub String);
/// Message for chat server communications
/// New chat session is created
#[derive(Message)]
#[rtype(usize)]
pub struct Connect {
pub addr: Recipient<WSMessage>,
}
/// Session is disconnected
#[derive(Message)]
pub struct Disconnect {
pub id: usize,
}
/// Send message to specific room
#[derive(Message)]
pub struct ClientMessage {
/// Id of the client session
pub id: usize,
/// Peer message
pub msg: String,
/// Room name
pub room: String,
}
#[derive(Serialize, Deserialize)]
pub struct StandardMessage {
/// Id of the client session
pub id: usize,
/// Peer message
pub msg: String,
}
impl actix::Message for StandardMessage {
type Result = String;
}
/// List of available rooms
pub struct ListRooms;
impl actix::Message for ListRooms {
type Result = Vec<String>;
}
/// Join room, if room does not exists create new one.
#[derive(Message)]
pub struct Join {
/// Client id
pub id: usize,
/// Room name
pub name: String,
}
#[derive(Serialize, Deserialize)]
pub struct Login {
pub username_or_email: String,
pub password: String
}
#[derive(Serialize, Deserialize)]
pub struct Register {
username: String,
email: Option<String>,
password: String,
password_verify: String
}
#[derive(Serialize, Deserialize)]
pub struct LoginResponse {
op: String,
jwt: String
}
#[derive(Serialize, Deserialize)]
pub struct CreateCommunity {
name: String,
auth: String
}
#[derive(Serialize, Deserialize)]
pub struct CreateCommunityResponse {
op: String,
community: Community
}
#[derive(Serialize, Deserialize)]
pub struct ListCommunities;
#[derive(Serialize, Deserialize)]
pub struct ListCommunitiesResponse {
op: String,
communities: Vec<Community>
}
#[derive(Serialize, Deserialize)]
pub struct CreatePost {
name: String,
url: Option<String>,
body: Option<String>,
community_id: i32,
auth: String
}
#[derive(Serialize, Deserialize)]
pub struct CreatePostResponse {
op: String,
post: Post
}
#[derive(Serialize, Deserialize)]
pub struct GetPost {
id: i32,
auth: Option<String>
}
#[derive(Serialize, Deserialize)]
pub struct GetPostResponse {
op: String,
post: Post,
comments: Vec<CommentView>
}
#[derive(Serialize, Deserialize)]
pub struct GetCommunity {
id: i32
}
#[derive(Serialize, Deserialize)]
pub struct GetCommunityResponse {
op: String,
community: Community
}
#[derive(Serialize, Deserialize)]
pub struct CreateComment {
content: String,
parent_id: Option<i32>,
post_id: i32,
auth: String
}
#[derive(Serialize, Deserialize)]
pub struct CreateCommentResponse {
op: String,
comment: CommentView
}
#[derive(Serialize, Deserialize)]
pub struct CreateCommentLike {
comment_id: i32,
post_id: i32,
score: i16,
auth: String
}
#[derive(Serialize, Deserialize)]
pub struct CreateCommentLikeResponse {
op: String,
comment: CommentView
}
/// `ChatServer` manages chat rooms and responsible for coordinating chat
/// session. implementation is super primitive
pub struct ChatServer {
sessions: HashMap<usize, Recipient<WSMessage>>, // A map from generated random ID to session addr
rooms: HashMap<i32, HashSet<usize>>, // A map from room / post name to set of connectionIDs
rng: ThreadRng,
}
impl Default for ChatServer {
fn default() -> ChatServer {
// default room
let rooms = HashMap::new();
ChatServer {
sessions: HashMap::new(),
rooms: rooms,
rng: rand::thread_rng(),
}
}
}
impl ChatServer {
/// Send message to all users in the room
fn send_room_message(&self, room: i32, message: &str,