This commit is contained in:
Nathan Sobo
2021-09-14 12:29:56 -06:00
parent 428c491542
commit f0019e3725
8 changed files with 135 additions and 31 deletions
+82 -6
View File
@@ -1,22 +1,73 @@
use crate::rpc::Client;
use crate::{
rpc::{Client, Status},
util::TryFutureExt,
};
use anyhow::{anyhow, Result};
use gpui::{elements::Image, executor, ImageData, Task};
use parking_lot::Mutex;
use postage::{prelude::Stream, sink::Sink, watch};
use std::{collections::HashMap, sync::Arc};
use surf::{
http::{Method, Request},
HttpClient, Url,
};
use zrpc::proto;
pub use proto::User;
pub struct User {
id: u64,
github_login: String,
avatar: Option<ImageData>,
}
pub struct UserStore {
users: Mutex<HashMap<u64, Arc<User>>>,
current_user: watch::Receiver<Option<Arc<User>>>,
rpc: Arc<Client>,
http: Arc<dyn HttpClient>,
_maintain_current_user: Option<Task<()>>,
}
impl UserStore {
pub fn new(rpc: Arc<Client>) -> Self {
Self {
pub fn new(
rpc: Arc<Client>,
http: Arc<dyn HttpClient>,
executor: &executor::Background,
) -> Arc<Self> {
let (mut current_user_tx, current_user_rx) = watch::channel();
let mut this = Arc::new(Self {
users: Default::default(),
rpc,
}
current_user: current_user_rx,
rpc: rpc.clone(),
http,
_maintain_current_user: None,
});
let task = {
let this = Arc::downgrade(&this);
executor.spawn(async move {
let mut status = rpc.status();
while let Some(status) = status.recv().await {
match status {
Status::Connected { user_id, .. } => {
if let Some(this) = this.upgrade() {
current_user_tx
.send(this.fetch_user(user_id).log_err().await)
.await
.ok();
}
}
Status::SignedOut => {
current_user_tx.send(None).await.ok();
}
_ => {}
}
}
})
};
Arc::get_mut(&mut this).unwrap()._maintain_current_user = Some(task);
this
}
pub async fn load_users(&self, mut user_ids: Vec<u64>) -> Result<()> {
@@ -56,4 +107,29 @@ impl UserStore {
Err(anyhow!("server responded with no users"))
}
}
pub fn current_user(&self) -> &watch::Receiver<Option<Arc<User>>> {
&self.current_user
}
}
impl User {
async fn new(message: proto::User, http: &dyn HttpClient) -> Self {
let avatar = fetch_avatar(http, &message.avatar_url).await.log_err();
User {
id: message.id,
github_login: message.github_login,
avatar,
}
}
}
async fn fetch_avatar(http: &dyn HttpClient, url: &str) -> Result<Arc<ImageData>> {
let url = Url::parse(url)?;
let request = Request::new(Method::Get, url);
let response = http.send(request).await?;
let bytes = response.body_bytes().await?;
let format = image::guess_format(&bytes)?;
let image = image::load_from_memory_with_format(&bytes, format)?.into_bgra8();
Ok(ImageData::new(image))
}