250 lines · 7.5 KB · Rust
RawDownload
use anyhow::Result;use gpui::{AppContext, AsyncAppContext, Context, Global, Model, ModelContext, SharedString, Task};use rpc::{    proto::{self, DevServerStatus},    TypedEnvelope,};use std::{collections::HashMap, sync::Arc}; use client::{Client, ProjectId};pub use client::{DevServerId, DevServerProjectId}; pub struct Store {    dev_server_projects: HashMap<DevServerProjectId, DevServerProject>,    dev_servers: HashMap<DevServerId, DevServer>,    _subscriptions: Vec<client::Subscription>,    client: Arc<Client>,} #[derive(Debug, Clone)]pub struct DevServerProject {    pub id: DevServerProjectId,    pub project_id: Option<ProjectId>,    pub path: SharedString,    pub dev_server_id: DevServerId,} impl From<proto::DevServerProject> for DevServerProject {    fn from(project: proto::DevServerProject) -> Self {        Self {            id: DevServerProjectId(project.id),            project_id: project.project_id.map(|id| ProjectId(id)),            path: project.path.into(),            dev_server_id: DevServerId(project.dev_server_id),        }    }} #[derive(Debug, Clone)]pub struct DevServer {    pub id: DevServerId,    pub name: SharedString,    pub ssh_connection_string: Option<SharedString>,    pub status: DevServerStatus,} impl From<proto::DevServer> for DevServer {    fn from(dev_server: proto::DevServer) -> Self {        Self {            id: DevServerId(dev_server.dev_server_id),            status: dev_server.status(),            name: dev_server.name.into(),            ssh_connection_string: dev_server.ssh_connection_string.map(|s| s.into()),        }    }} struct GlobalStore(Model<Store>); impl Global for GlobalStore {} pub fn init(client: Arc<Client>, cx: &mut AppContext) {    let store = cx.new_model(|cx| Store::new(client, cx));    cx.set_global(GlobalStore(store));} impl Store {    pub fn global(cx: &AppContext) -> Model<Store> {        cx.global::<GlobalStore>().0.clone()    }     pub fn new(client: Arc<Client>, cx: &ModelContext<Self>) -> Self {        Self {            dev_server_projects: Default::default(),            dev_servers: Default::default(),            _subscriptions: vec![client                .add_message_handler(cx.weak_model(), Self::handle_dev_server_projects_update)],            client,        }    }     pub fn projects_for_server(&self, id: DevServerId) -> Vec<DevServerProject> {        let mut projects: Vec<DevServerProject> = self            .dev_server_projects            .values()            .filter(|project| project.dev_server_id == id)            .cloned()            .collect();        projects.sort_by_key(|p| (p.path.clone(), p.id));        projects    }     pub fn dev_servers(&self) -> Vec<DevServer> {        let mut dev_servers: Vec<DevServer> = self.dev_servers.values().cloned().collect();        dev_servers.sort_by_key(|d| (d.status == DevServerStatus::Offline, d.name.clone(), d.id));        dev_servers    }     pub fn dev_server(&self, id: DevServerId) -> Option<&DevServer> {        self.dev_servers.get(&id)    }     pub fn dev_server_status(&self, id: DevServerId) -> DevServerStatus {        self.dev_server(id)            .map(|server| server.status)            .unwrap_or(DevServerStatus::Offline)    }     pub fn dev_server_projects(&self) -> Vec<DevServerProject> {        let mut projects: Vec<DevServerProject> =            self.dev_server_projects.values().cloned().collect();        projects.sort_by_key(|p| (p.path.clone(), p.id));        projects    }     pub fn dev_server_project(&self, id: DevServerProjectId) -> Option<&DevServerProject> {        self.dev_server_projects.get(&id)    }     pub fn dev_server_for_project(&self, id: DevServerProjectId) -> Option<&DevServer> {        self.dev_server_project(id)            .and_then(|project| self.dev_server(project.dev_server_id))    }     async fn handle_dev_server_projects_update(        this: Model<Self>,        envelope: TypedEnvelope<proto::DevServerProjectsUpdate>,        _: Arc<Client>,        mut cx: AsyncAppContext,    ) -> Result<()> {        this.update(&mut cx, |this, cx| {            this.dev_servers = envelope                .payload                .dev_servers                .into_iter()                .map(|dev_server| (DevServerId(dev_server.dev_server_id), dev_server.into()))                .collect();            this.dev_server_projects = envelope                .payload                .dev_server_projects                .into_iter()                .map(|project| (DevServerProjectId(project.id), project.into()))                .collect();             cx.notify();        })?;        Ok(())    }     pub fn create_dev_server_project(        &mut self,        dev_server_id: DevServerId,        path: String,        cx: &mut ModelContext<Self>,    ) -> Task<Result<proto::CreateDevServerProjectResponse>> {        let client = self.client.clone();        cx.background_executor().spawn(async move {            client                .request(proto::CreateDevServerProject {                    dev_server_id: dev_server_id.0,                    path,                })                .await        })    }     pub fn create_dev_server(        &mut self,        name: String,        ssh_connection_string: Option<String>,        cx: &mut ModelContext<Self>,    ) -> Task<Result<proto::CreateDevServerResponse>> {        let client = self.client.clone();        cx.background_executor().spawn(async move {            let result = client                .request(proto::CreateDevServer {                    name,                    ssh_connection_string,                })                .await?;            Ok(result)        })    }     pub fn rename_dev_server(        &mut self,        dev_server_id: DevServerId,        name: String,        ssh_connection_string: Option<String>,        cx: &mut ModelContext<Self>,    ) -> Task<Result<()>> {        let client = self.client.clone();        cx.background_executor().spawn(async move {            client                .request(proto::RenameDevServer {                    dev_server_id: dev_server_id.0,                    name,                    ssh_connection_string,                })                .await?;            Ok(())        })    }     pub fn regenerate_dev_server_token(        &mut self,        dev_server_id: DevServerId,        cx: &mut ModelContext<Self>,    ) -> Task<Result<proto::RegenerateDevServerTokenResponse>> {        let client = self.client.clone();        cx.background_executor().spawn(async move {            client                .request(proto::RegenerateDevServerToken {                    dev_server_id: dev_server_id.0,                })                .await        })    }     pub fn delete_dev_server(        &mut self,        id: DevServerId,        cx: &mut ModelContext<Self>,    ) -> Task<Result<()>> {        let client = self.client.clone();        cx.background_executor().spawn(async move {            client                .request(proto::DeleteDevServer {                    dev_server_id: id.0,                })                .await?;            Ok(())        })    }     pub fn delete_dev_server_project(        &mut self,        id: DevServerProjectId,        cx: &mut ModelContext<Self>,    ) -> Task<Result<()>> {        let client = self.client.clone();        cx.background_executor().spawn(async move {            client                .request(proto::DeleteDevServerProject {                    dev_server_project_id: id.0,                })                .await?;            Ok(())        })    }}