2020-04-06 08:38:08 +02:00
|
|
|
use actix::{Actor, Addr, StreamHandler};
|
|
|
|
use actix_web::web::Data;
|
2020-04-05 15:15:09 +02:00
|
|
|
use actix_web::{get, web, Error, HttpRequest, HttpResponse};
|
|
|
|
use actix_web_actors::ws;
|
|
|
|
|
2020-04-08 20:26:28 +02:00
|
|
|
use jirs_data::WsMsg;
|
2020-04-05 15:15:09 +02:00
|
|
|
|
2020-04-06 22:59:33 +02:00
|
|
|
use crate::db::authorize_user::AuthorizeUser;
|
2020-04-16 16:11:19 +02:00
|
|
|
use crate::db::tokens::FindBindToken;
|
2020-04-06 08:38:08 +02:00
|
|
|
use crate::db::DbExecutor;
|
2020-04-17 14:10:05 +02:00
|
|
|
use crate::mail::MailExecutor;
|
2020-04-06 08:38:08 +02:00
|
|
|
|
2020-04-16 16:11:19 +02:00
|
|
|
pub mod auth;
|
2020-04-11 11:18:41 +02:00
|
|
|
pub mod comments;
|
|
|
|
pub mod issues;
|
|
|
|
pub mod projects;
|
|
|
|
pub mod users;
|
|
|
|
|
|
|
|
pub type WsResult = std::result::Result<Option<WsMsg>, WsMsg>;
|
|
|
|
|
|
|
|
pub fn current_user(current_user: &Option<jirs_data::User>) -> Result<&jirs_data::User, WsMsg> {
|
|
|
|
current_user
|
|
|
|
.as_ref()
|
|
|
|
.map(|u| u)
|
|
|
|
.ok_or_else(|| WsMsg::AuthorizeExpired)
|
|
|
|
}
|
2020-04-08 20:26:28 +02:00
|
|
|
|
2020-04-06 22:59:33 +02:00
|
|
|
trait WsMessageSender {
|
|
|
|
fn send_msg(&mut self, msg: jirs_data::WsMsg);
|
|
|
|
}
|
|
|
|
|
2020-04-06 08:38:08 +02:00
|
|
|
struct WebSocketActor {
|
|
|
|
db: Data<Addr<DbExecutor>>,
|
2020-04-17 14:10:05 +02:00
|
|
|
mail: Data<Addr<MailExecutor>>,
|
2020-04-06 22:59:33 +02:00
|
|
|
current_user: Option<jirs_data::User>,
|
2020-04-06 08:38:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Actor for WebSocketActor {
|
2020-04-06 22:59:33 +02:00
|
|
|
type Context = ws::WebsocketContext<WebSocketActor>;
|
2020-04-05 15:15:09 +02:00
|
|
|
}
|
|
|
|
|
2020-04-06 22:59:33 +02:00
|
|
|
impl WsMessageSender for ws::WebsocketContext<WebSocketActor> {
|
|
|
|
fn send_msg(&mut self, msg: WsMsg) {
|
|
|
|
self.binary(bincode::serialize(&msg).unwrap())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl WebSocketActor {
|
2020-04-08 20:26:28 +02:00
|
|
|
fn handle_ws_msg(&mut self, msg: WsMsg) -> WsResult {
|
2020-04-06 08:38:08 +02:00
|
|
|
use futures::executor::block_on;
|
|
|
|
|
2020-04-08 20:26:28 +02:00
|
|
|
if msg != WsMsg::Ping && msg != WsMsg::Pong {
|
2020-04-10 22:33:07 +02:00
|
|
|
info!("incoming message: {:?}", msg);
|
2020-04-08 20:26:28 +02:00
|
|
|
}
|
|
|
|
|
2020-04-17 14:10:05 +02:00
|
|
|
let msg =
|
|
|
|
match msg {
|
|
|
|
WsMsg::Ping => Some(WsMsg::Pong),
|
|
|
|
WsMsg::Pong => Some(WsMsg::Ping),
|
|
|
|
|
|
|
|
// Issues
|
|
|
|
WsMsg::IssueUpdateRequest(id, field_id, payload) => block_on(
|
|
|
|
issues::update_issue(&self.db, &self.current_user, id, field_id, payload),
|
|
|
|
)?,
|
|
|
|
WsMsg::IssueCreateRequest(payload) => {
|
|
|
|
block_on(issues::add_issue(&self.db, &self.current_user, payload))?
|
|
|
|
}
|
|
|
|
WsMsg::IssueDeleteRequest(id) => {
|
|
|
|
block_on(issues::delete_issue(&self.db, &self.current_user, id))?
|
|
|
|
}
|
|
|
|
WsMsg::ProjectIssuesRequest => {
|
|
|
|
block_on(issues::load_issues(&self.db, &self.current_user))?
|
|
|
|
}
|
|
|
|
|
|
|
|
// projects
|
|
|
|
WsMsg::ProjectRequest => {
|
|
|
|
block_on(projects::current_project(&self.db, &self.current_user))?
|
|
|
|
}
|
|
|
|
|
|
|
|
WsMsg::ProjectUpdateRequest(payload) => block_on(projects::update_project(
|
|
|
|
&self.db,
|
|
|
|
&self.current_user,
|
|
|
|
payload,
|
|
|
|
))?,
|
|
|
|
|
|
|
|
// auth
|
|
|
|
WsMsg::AuthorizeRequest(uuid) => block_on(self.check_auth_token(uuid))?,
|
|
|
|
WsMsg::BindTokenCheck(uuid) => block_on(self.check_bind_token(uuid))?,
|
|
|
|
WsMsg::AuthenticateRequest(email, name) => {
|
|
|
|
block_on(auth::authenticate(&self.db, &self.mail, name, email))?
|
|
|
|
}
|
|
|
|
|
2020-04-17 20:44:55 +02:00
|
|
|
// register
|
|
|
|
WsMsg::SignUpRequest(email, username) => {
|
|
|
|
block_on(users::register(&self.db, &self.mail, username, email))?
|
|
|
|
}
|
|
|
|
|
2020-04-17 14:10:05 +02:00
|
|
|
// users
|
|
|
|
WsMsg::ProjectUsersRequest => {
|
|
|
|
block_on(users::load_project_users(&self.db, &self.current_user))?
|
|
|
|
}
|
|
|
|
|
|
|
|
// comments
|
|
|
|
WsMsg::IssueCommentsRequest(issue_id) => block_on(comments::load_issues(
|
|
|
|
&self.db,
|
|
|
|
&self.current_user,
|
|
|
|
issue_id,
|
|
|
|
))?,
|
|
|
|
|
|
|
|
WsMsg::CreateComment(payload) => block_on(comments::create_comment(
|
|
|
|
&self.db,
|
|
|
|
&self.current_user,
|
|
|
|
payload,
|
|
|
|
))?,
|
|
|
|
|
|
|
|
WsMsg::UpdateComment(payload) => block_on(comments::update_comment(
|
|
|
|
&self.db,
|
|
|
|
&self.current_user,
|
|
|
|
payload,
|
|
|
|
))?,
|
|
|
|
|
|
|
|
WsMsg::CommentDeleteRequest(comment_id) => block_on(comments::delete_comment(
|
|
|
|
&self.db,
|
|
|
|
&self.current_user,
|
|
|
|
comment_id,
|
|
|
|
))?,
|
|
|
|
|
|
|
|
// else fail
|
|
|
|
_ => {
|
|
|
|
error!("No handle for {:?} specified", msg);
|
|
|
|
None
|
|
|
|
}
|
|
|
|
};
|
2020-04-14 16:20:05 +02:00
|
|
|
if msg.is_some() && msg != Some(WsMsg::Pong) {
|
|
|
|
info!("sending message {:?}", msg);
|
|
|
|
}
|
2020-04-08 20:26:28 +02:00
|
|
|
Ok(msg)
|
2020-04-06 22:59:33 +02:00
|
|
|
}
|
|
|
|
|
2020-04-16 16:11:19 +02:00
|
|
|
async fn check_auth_token(&mut self, token: uuid::Uuid) -> WsResult {
|
2020-04-08 20:26:28 +02:00
|
|
|
let m = match self
|
2020-04-06 22:59:33 +02:00
|
|
|
.db
|
|
|
|
.send(AuthorizeUser {
|
|
|
|
access_token: token,
|
|
|
|
})
|
|
|
|
.await
|
|
|
|
{
|
2020-04-08 20:26:28 +02:00
|
|
|
Ok(Ok(u)) => {
|
|
|
|
let user: jirs_data::User = u.into();
|
|
|
|
self.current_user = Some(user.clone());
|
|
|
|
Some(WsMsg::AuthorizeLoaded(Ok(user)))
|
|
|
|
}
|
|
|
|
Ok(Err(_)) => Some(WsMsg::AuthorizeLoaded(
|
|
|
|
Err("Invalid auth token".to_string()),
|
|
|
|
)),
|
|
|
|
_ => Some(WsMsg::AuthorizeExpired),
|
|
|
|
};
|
|
|
|
Ok(m)
|
|
|
|
}
|
2020-04-16 16:11:19 +02:00
|
|
|
|
|
|
|
async fn check_bind_token(&mut self, bind_token: uuid::Uuid) -> WsResult {
|
|
|
|
let token: crate::models::Token =
|
|
|
|
match self.db.send(FindBindToken { token: bind_token }).await {
|
|
|
|
Ok(Ok(token)) => token,
|
|
|
|
Ok(Err(_)) => return Ok(Some(WsMsg::BindTokenBad)),
|
|
|
|
_ => return Ok(None),
|
|
|
|
};
|
|
|
|
Ok(Some(WsMsg::BindTokenOk(token.access_token)))
|
|
|
|
}
|
2020-04-06 22:59:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WebSocketActor {
|
|
|
|
fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
|
2020-04-05 15:15:09 +02:00
|
|
|
match msg {
|
|
|
|
Ok(ws::Message::Ping(msg)) => ctx.pong(&msg),
|
|
|
|
Ok(ws::Message::Text(text)) => ctx.text(text),
|
2020-04-06 22:59:33 +02:00
|
|
|
|
2020-04-06 08:38:08 +02:00
|
|
|
Ok(ws::Message::Binary(bin)) => {
|
|
|
|
let ws_msg: bincode::Result<jirs_data::WsMsg> =
|
|
|
|
bincode::deserialize(bin.to_vec().as_slice());
|
2020-04-06 22:59:33 +02:00
|
|
|
let msg = match ws_msg {
|
2020-04-08 20:26:28 +02:00
|
|
|
Ok(m) => m,
|
2020-04-06 22:59:33 +02:00
|
|
|
_ => return,
|
|
|
|
};
|
2020-04-08 20:26:28 +02:00
|
|
|
match self.handle_ws_msg(msg) {
|
|
|
|
Ok(Some(msg)) => ctx.send_msg(msg),
|
|
|
|
Err(e) => ctx.send_msg(e),
|
|
|
|
_ => (),
|
2020-04-06 08:38:08 +02:00
|
|
|
};
|
|
|
|
}
|
2020-04-05 15:15:09 +02:00
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[get("/ws/")]
|
2020-04-06 08:38:08 +02:00
|
|
|
pub async fn index(
|
|
|
|
req: HttpRequest,
|
|
|
|
stream: web::Payload,
|
|
|
|
db: Data<Addr<DbExecutor>>,
|
2020-04-17 14:10:05 +02:00
|
|
|
mail: Data<Addr<MailExecutor>>,
|
2020-04-06 08:38:08 +02:00
|
|
|
) -> Result<HttpResponse, Error> {
|
2020-04-06 22:59:33 +02:00
|
|
|
ws::start(
|
|
|
|
WebSocketActor {
|
|
|
|
db,
|
2020-04-17 14:10:05 +02:00
|
|
|
mail,
|
2020-04-06 22:59:33 +02:00
|
|
|
current_user: None,
|
|
|
|
},
|
|
|
|
&req,
|
|
|
|
stream,
|
|
|
|
)
|
2020-04-05 15:15:09 +02:00
|
|
|
}
|