Preallocations
This commit is contained in:
parent
146be0184b
commit
c8730485d0
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -2042,9 +2042,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.94"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
|
||||
checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765"
|
||||
|
||||
[[package]]
|
||||
name = "line-wrap"
|
||||
|
@ -16,6 +16,7 @@ use jirs_data::{User, UserId, WsMsg};
|
||||
use websocket_actor::server::InnerMsg::BroadcastToChannel;
|
||||
use websocket_actor::server::WsServer;
|
||||
|
||||
#[cfg(feature = "aws-s3")]
|
||||
#[post("/")]
|
||||
pub async fn upload(
|
||||
mut payload: Multipart,
|
||||
@ -80,11 +81,74 @@ pub async fn upload(
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "aws-s3"))]
|
||||
#[post("/")]
|
||||
pub async fn upload(
|
||||
mut payload: Multipart,
|
||||
db: Data<Addr<DbExecutor>>,
|
||||
ws: Data<Addr<WsServer>>,
|
||||
fs: Data<Addr<filesystem_actor::FileSystemExecutor>>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let mut user_id: Option<UserId> = None;
|
||||
let mut avatar_url: Option<String> = None;
|
||||
|
||||
while let Ok(Some(field)) = payload.try_next().await {
|
||||
let disposition: ContentDisposition = match field.content_disposition() {
|
||||
Some(d) => d,
|
||||
_ => continue,
|
||||
};
|
||||
if !disposition.is_form_data() {
|
||||
return Ok(HttpResponse::BadRequest().finish());
|
||||
}
|
||||
match disposition.get_name() {
|
||||
Some("token") => {
|
||||
user_id = Some(handle_token(field, db.clone()).await?);
|
||||
}
|
||||
Some("avatar") => {
|
||||
let id = user_id.ok_or_else(|| HttpResponse::Unauthorized().finish())?;
|
||||
avatar_url = Some(
|
||||
crate::handlers::upload_avatar_image::handle_image(
|
||||
id,
|
||||
field,
|
||||
disposition,
|
||||
fs.clone(),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
}
|
||||
let user_id = match user_id {
|
||||
Some(id) => id,
|
||||
_ => return Ok(HttpResponse::Unauthorized().finish()),
|
||||
};
|
||||
|
||||
let project_id = match block_on(db.send(CurrentUserProject { user_id })) {
|
||||
Ok(Ok(user_project)) => user_project.project_id,
|
||||
_ => return Ok(HttpResponse::UnprocessableEntity().finish()),
|
||||
};
|
||||
|
||||
match (user_id, avatar_url) {
|
||||
(user_id, Some(avatar_url)) => {
|
||||
let user = update_user_avatar(user_id, avatar_url.clone(), db).await?;
|
||||
ws.send(BroadcastToChannel(
|
||||
project_id,
|
||||
WsMsg::AvatarUrlChanged(user.id, avatar_url),
|
||||
))
|
||||
.await
|
||||
.map_err(|_| HttpResponse::UnprocessableEntity().finish())?;
|
||||
Ok(HttpResponse::NoContent().finish())
|
||||
}
|
||||
_ => Ok(HttpResponse::UnprocessableEntity().finish()),
|
||||
}
|
||||
}
|
||||
|
||||
async fn update_user_avatar(
|
||||
user_id: UserId,
|
||||
new_url: String,
|
||||
db: Data<Addr<DbExecutor>>,
|
||||
) -> Result<User, Error> {
|
||||
) -> Result<User, actix_web::Error> {
|
||||
match db
|
||||
.send(UpdateAvatarUrl {
|
||||
user_id,
|
||||
@ -96,16 +160,23 @@ async fn update_user_avatar(
|
||||
|
||||
Ok(Err(e)) => {
|
||||
error!("{:?}", e);
|
||||
Err(HttpResponse::Unauthorized().finish().into())
|
||||
Err(actix_web::Error::from(
|
||||
HttpResponse::Unauthorized().finish(),
|
||||
))
|
||||
}
|
||||
Err(e) => {
|
||||
error!("{:?}", e);
|
||||
Err(HttpResponse::Unauthorized().finish().into())
|
||||
Err(actix_web::Error::from(
|
||||
HttpResponse::Unauthorized().finish(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_token(mut field: Field, db: Data<Addr<DbExecutor>>) -> Result<UserId, Error> {
|
||||
async fn handle_token(
|
||||
mut field: Field,
|
||||
db: Data<Addr<DbExecutor>>,
|
||||
) -> Result<UserId, actix_web::Error> {
|
||||
let mut f: Vec<u8> = vec![];
|
||||
while let Some(chunk) = field.next().await {
|
||||
let data = chunk.unwrap();
|
||||
|
@ -29,9 +29,9 @@ flate2 = { version = "*" }
|
||||
syntect = { version = "*" }
|
||||
lazy_static = { version = "*" }
|
||||
|
||||
log = "0.4"
|
||||
pretty_env_logger = "0.4"
|
||||
env_logger = "0.7"
|
||||
log = { version = "0.4" }
|
||||
pretty_env_logger = { version = "0.4" }
|
||||
env_logger = { version = "0.7" }
|
||||
|
||||
uuid = { version = "0.8.1", features = ["serde", "v4", "v5"] }
|
||||
|
||||
|
@ -7,10 +7,8 @@ use jirs_data::msg::WsError;
|
||||
use jirs_data::{Token, WsMsg};
|
||||
use mail_actor::welcome::Welcome;
|
||||
|
||||
use crate::{
|
||||
db_or_debug_and_return, db_or_debug_or_fallback, mail_or_debug_and_return, WebSocketActor,
|
||||
WsHandler, WsResult,
|
||||
};
|
||||
use crate::server::InnerMsg;
|
||||
use crate::{db_or_debug_and_return, db_or_debug_or_fallback, mail_or_debug_and_return, *};
|
||||
|
||||
pub struct Authenticate {
|
||||
pub name: String,
|
||||
@ -69,7 +67,7 @@ impl WsHandler<CheckAuthToken> for WebSocketActor {
|
||||
self.current_user_project = self.load_user_project().ok();
|
||||
self.current_project = self.load_project().ok();
|
||||
|
||||
block_on(self.join_channel(ctx.address().recipient()));
|
||||
block_on(self.join_channel(ctx.address().recipient::<InnerMsg>()));
|
||||
Ok(Some(WsMsg::AuthorizeLoaded(Ok((user, setting)))))
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use jirs_data::{
|
||||
DescriptionString, EndsAt, EpicId, IssueType, NameString, StartsAt, UserProject, WsMsg,
|
||||
};
|
||||
|
||||
use crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult};
|
||||
use crate::{db_or_debug_and_return, *};
|
||||
|
||||
pub struct LoadEpics;
|
||||
|
||||
|
@ -26,7 +26,7 @@ trait WsMessageSender {
|
||||
fn send_msg(&mut self, msg: &jirs_data::WsMsg);
|
||||
}
|
||||
|
||||
struct WebSocketActor {
|
||||
pub struct WebSocketActor {
|
||||
db: Data<Addr<DbExecutor>>,
|
||||
mail: Data<Addr<MailExecutor>>,
|
||||
addr: Addr<WsServer>,
|
||||
@ -36,13 +36,20 @@ struct WebSocketActor {
|
||||
current_project: Option<jirs_data::Project>,
|
||||
}
|
||||
|
||||
impl Actor for WebSocketActor {
|
||||
type Context = ws::WebsocketContext<WebSocketActor>;
|
||||
pub type WsCtx = ws::WebsocketContext<WebSocketActor>;
|
||||
|
||||
impl actix::Actor for WebSocketActor {
|
||||
type Context = WsCtx;
|
||||
}
|
||||
|
||||
impl WsMessageSender for ws::WebsocketContext<WebSocketActor> {
|
||||
fn send_msg(&mut self, msg: &WsMsg) {
|
||||
self.binary(bincode::serialize(msg).unwrap())
|
||||
match bincode::serialize(msg) {
|
||||
Err(err) => {
|
||||
log::error!("{}", err);
|
||||
}
|
||||
Ok(v) => self.binary(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,7 +335,7 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WebSocketActor {
|
||||
self.addr.do_send(InnerMsg::Leave(
|
||||
up.project_id,
|
||||
user.id,
|
||||
ctx.address().recipient(),
|
||||
ctx.address().recipient::<InnerMsg>(),
|
||||
));
|
||||
}
|
||||
ctx.stop()
|
||||
@ -337,7 +344,7 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WebSocketActor {
|
||||
|
||||
pub trait WsHandler<Message>
|
||||
where
|
||||
Self: Actor,
|
||||
Self: actix::Actor<Context = WsCtx>,
|
||||
{
|
||||
fn handle_msg(&mut self, msg: Message, _ctx: &mut <Self as Actor>::Context) -> WsResult;
|
||||
}
|
||||
|
@ -280,7 +280,7 @@ impl Model {
|
||||
issue_form: None,
|
||||
project_form: None,
|
||||
comment_form: None,
|
||||
comments_by_project_id: Default::default(),
|
||||
comments_by_project_id: HashMap::with_capacity(1_000),
|
||||
page_content: page.build_content(),
|
||||
page,
|
||||
host_url,
|
||||
@ -291,22 +291,22 @@ impl Model {
|
||||
messages_tooltip_visible: false,
|
||||
issues: vec![],
|
||||
users: vec![],
|
||||
users_by_id: Default::default(),
|
||||
users_by_id: HashMap::with_capacity(1_000),
|
||||
user_settings: None,
|
||||
comments: vec![],
|
||||
comments_by_id: Default::default(),
|
||||
comments_by_id: HashMap::with_capacity(1_000),
|
||||
issue_statuses: vec![],
|
||||
issue_statuses_by_id: Default::default(),
|
||||
issue_statuses_by_name: Default::default(),
|
||||
issue_statuses_by_id: HashMap::with_capacity(1_000),
|
||||
issue_statuses_by_name: HashMap::with_capacity(1_000),
|
||||
messages: vec![],
|
||||
user_projects: vec![],
|
||||
projects: vec![],
|
||||
epics: vec![],
|
||||
issues_by_id: Default::default(),
|
||||
issues_by_id: HashMap::with_capacity(1_000),
|
||||
show_extras: false,
|
||||
epics_by_id: Default::default(),
|
||||
epics_by_id: HashMap::with_capacity(1_000),
|
||||
modals_stack: vec![],
|
||||
modals: Default::default(),
|
||||
modals: Modals::default(),
|
||||
key_triggers: std::rc::Rc::new(std::cell::RefCell::new(HashMap::with_capacity(20))),
|
||||
distinct_key_up: crate::shared::on_event::distinct(),
|
||||
}
|
||||
|
@ -16,12 +16,15 @@ impl EpicsPage {
|
||||
}
|
||||
|
||||
pub fn build_issues_per_epic(model: &Model) -> HashMap<EpicId, Vec<IssueId>> {
|
||||
model.issues().iter().fold(HashMap::new(), |mut h, issue| {
|
||||
if let Some(epic_id) = issue.epic_id.as_ref() {
|
||||
h.entry(*epic_id).or_default().push(issue.id);
|
||||
}
|
||||
h
|
||||
})
|
||||
model.issues().iter().fold(
|
||||
HashMap::with_capacity(model.issues().len()),
|
||||
|mut h, issue| {
|
||||
if let Some(epic_id) = issue.epic_id.as_ref() {
|
||||
h.entry(*epic_id).or_default().push(issue.id);
|
||||
}
|
||||
h
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn issues(&self, epic_id: EpicId) -> Option<&Vec<IssueId>> {
|
||||
|
@ -130,7 +130,7 @@ async fn update_avatar(data: FormData, host_url: String) -> Option<Msg> {
|
||||
let path = format!("{}/avatar/", host_url);
|
||||
let result = Request::new(path)
|
||||
.method(Method::Post)
|
||||
.body(data.into())
|
||||
.body(&data)
|
||||
.fetch()
|
||||
.await;
|
||||
let response = match result {
|
||||
|
@ -68,10 +68,15 @@ impl ProjectPage {
|
||||
issues.collect()
|
||||
};
|
||||
|
||||
let issues_per_epic_id = issues.into_iter().fold(HashMap::new(), |mut m, issue| {
|
||||
m.entry(issue.epic_id).or_insert_with(Vec::new).push(issue);
|
||||
m
|
||||
});
|
||||
let issues_per_epic_id = {
|
||||
let issues_len = issues.len();
|
||||
issues
|
||||
.into_iter()
|
||||
.fold(HashMap::with_capacity(issues_len), |mut m, issue| {
|
||||
m.entry(issue.epic_id).or_insert_with(Vec::new).push(issue);
|
||||
m
|
||||
})
|
||||
};
|
||||
|
||||
epics
|
||||
.map(|epic| {
|
||||
|
@ -1,7 +1,6 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use jirs_data::{IssueStatus, IssueStatusId, ProjectFieldId, UpdateProjectPayload, WsMsg};
|
||||
use seed::error;
|
||||
use seed::prelude::Orders;
|
||||
|
||||
use crate::components::styled_select::StyledSelectChanged;
|
||||
|
@ -15,10 +15,7 @@ path = "./src/main.rs"
|
||||
[features]
|
||||
aws-s3 = ["amazon-actor"]
|
||||
local-storage = ["filesystem-actor"]
|
||||
default = [
|
||||
"aws-s3",
|
||||
"local-storage",
|
||||
]
|
||||
default = ["local-storage"]
|
||||
|
||||
[dependencies]
|
||||
actix = { version = "0.10.0" }
|
||||
|
@ -20,9 +20,10 @@ hi = []
|
||||
mail = []
|
||||
web = ["aws-s3", "local-storage"]
|
||||
websocket = []
|
||||
default = ["local-storage", "database", "hi", "mail", "web", "websocket"]
|
||||
|
||||
[dependencies]
|
||||
serde = "*"
|
||||
serde = { version = "*" }
|
||||
toml = { version = "*" }
|
||||
|
||||
# Amazon S3
|
||||
|
@ -17,8 +17,8 @@ backend = ["diesel", "actix", "derive_enum_sql"]
|
||||
frontend = []
|
||||
|
||||
[dependencies]
|
||||
serde = "*"
|
||||
serde_json = "*"
|
||||
serde = { version = "*" }
|
||||
serde_json = { version = "*" }
|
||||
chrono = { version = "*", features = ["serde"] }
|
||||
uuid = { version = ">=0.7.0, <0.9.0", features = ["serde"] }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user