dev_server_projects.rs

  1use anyhow::Result;
  2use gpui::{AppContext, AsyncAppContext, Context, Global, Model, ModelContext, SharedString, Task};
  3use rpc::{
  4    proto::{self, DevServerStatus},
  5    TypedEnvelope,
  6};
  7use std::{collections::HashMap, sync::Arc};
  8
  9use client::{Client, ProjectId};
 10pub use client::{DevServerId, DevServerProjectId};
 11
 12pub struct Store {
 13    dev_server_projects: HashMap<DevServerProjectId, DevServerProject>,
 14    dev_servers: HashMap<DevServerId, DevServer>,
 15    _subscriptions: Vec<client::Subscription>,
 16    client: Arc<Client>,
 17}
 18
 19#[derive(Debug, Clone)]
 20pub struct DevServerProject {
 21    pub id: DevServerProjectId,
 22    pub project_id: Option<ProjectId>,
 23    pub path: SharedString,
 24    pub dev_server_id: DevServerId,
 25}
 26
 27impl From<proto::DevServerProject> for DevServerProject {
 28    fn from(project: proto::DevServerProject) -> Self {
 29        Self {
 30            id: DevServerProjectId(project.id),
 31            project_id: project.project_id.map(|id| ProjectId(id)),
 32            path: project.path.into(),
 33            dev_server_id: DevServerId(project.dev_server_id),
 34        }
 35    }
 36}
 37
 38#[derive(Debug, Clone)]
 39pub struct DevServer {
 40    pub id: DevServerId,
 41    pub name: SharedString,
 42    pub status: DevServerStatus,
 43}
 44
 45impl From<proto::DevServer> for DevServer {
 46    fn from(dev_server: proto::DevServer) -> Self {
 47        Self {
 48            id: DevServerId(dev_server.dev_server_id),
 49            status: dev_server.status(),
 50            name: dev_server.name.into(),
 51        }
 52    }
 53}
 54
 55struct GlobalStore(Model<Store>);
 56
 57impl Global for GlobalStore {}
 58
 59pub fn init(client: Arc<Client>, cx: &mut AppContext) {
 60    let store = cx.new_model(|cx| Store::new(client, cx));
 61    cx.set_global(GlobalStore(store));
 62}
 63
 64impl Store {
 65    pub fn global(cx: &AppContext) -> Model<Store> {
 66        cx.global::<GlobalStore>().0.clone()
 67    }
 68
 69    pub fn new(client: Arc<Client>, cx: &ModelContext<Self>) -> Self {
 70        Self {
 71            dev_server_projects: Default::default(),
 72            dev_servers: Default::default(),
 73            _subscriptions: vec![client
 74                .add_message_handler(cx.weak_model(), Self::handle_dev_server_projects_update)],
 75            client,
 76        }
 77    }
 78
 79    pub fn projects_for_server(&self, id: DevServerId) -> Vec<DevServerProject> {
 80        let mut projects: Vec<DevServerProject> = self
 81            .dev_server_projects
 82            .values()
 83            .filter(|project| project.dev_server_id == id)
 84            .cloned()
 85            .collect();
 86        projects.sort_by_key(|p| (p.path.clone(), p.id));
 87        projects
 88    }
 89
 90    pub fn dev_servers(&self) -> Vec<DevServer> {
 91        let mut dev_servers: Vec<DevServer> = self.dev_servers.values().cloned().collect();
 92        dev_servers.sort_by_key(|d| (d.status == DevServerStatus::Offline, d.name.clone(), d.id));
 93        dev_servers
 94    }
 95
 96    pub fn dev_server(&self, id: DevServerId) -> Option<&DevServer> {
 97        self.dev_servers.get(&id)
 98    }
 99
100    pub fn dev_server_status(&self, id: DevServerId) -> DevServerStatus {
101        self.dev_server(id)
102            .map(|server| server.status)
103            .unwrap_or(DevServerStatus::Offline)
104    }
105
106    pub fn dev_server_projects(&self) -> Vec<DevServerProject> {
107        let mut projects: Vec<DevServerProject> =
108            self.dev_server_projects.values().cloned().collect();
109        projects.sort_by_key(|p| (p.path.clone(), p.id));
110        projects
111    }
112
113    pub fn dev_server_project(&self, id: DevServerProjectId) -> Option<&DevServerProject> {
114        self.dev_server_projects.get(&id)
115    }
116
117    pub fn dev_server_for_project(&self, id: DevServerProjectId) -> Option<&DevServer> {
118        self.dev_server_project(id)
119            .and_then(|project| self.dev_server(project.dev_server_id))
120    }
121
122    async fn handle_dev_server_projects_update(
123        this: Model<Self>,
124        envelope: TypedEnvelope<proto::DevServerProjectsUpdate>,
125        _: Arc<Client>,
126        mut cx: AsyncAppContext,
127    ) -> Result<()> {
128        this.update(&mut cx, |this, cx| {
129            this.dev_servers = envelope
130                .payload
131                .dev_servers
132                .into_iter()
133                .map(|dev_server| (DevServerId(dev_server.dev_server_id), dev_server.into()))
134                .collect();
135            this.dev_server_projects = envelope
136                .payload
137                .dev_server_projects
138                .into_iter()
139                .map(|project| (DevServerProjectId(project.id), project.into()))
140                .collect();
141
142            cx.notify();
143        })?;
144        Ok(())
145    }
146
147    pub fn create_dev_server_project(
148        &mut self,
149        dev_server_id: DevServerId,
150        path: String,
151        cx: &mut ModelContext<Self>,
152    ) -> Task<Result<proto::CreateDevServerProjectResponse>> {
153        let client = self.client.clone();
154        cx.background_executor().spawn(async move {
155            client
156                .request(proto::CreateDevServerProject {
157                    dev_server_id: dev_server_id.0,
158                    path,
159                })
160                .await
161        })
162    }
163
164    pub fn create_dev_server(
165        &mut self,
166        name: String,
167        cx: &mut ModelContext<Self>,
168    ) -> Task<Result<proto::CreateDevServerResponse>> {
169        let client = self.client.clone();
170        cx.background_executor().spawn(async move {
171            let result = client.request(proto::CreateDevServer { name }).await?;
172            Ok(result)
173        })
174    }
175
176    pub fn delete_dev_server(
177        &mut self,
178        id: DevServerId,
179        cx: &mut ModelContext<Self>,
180    ) -> Task<Result<()>> {
181        let client = self.client.clone();
182        cx.background_executor().spawn(async move {
183            client
184                .request(proto::DeleteDevServer {
185                    dev_server_id: id.0,
186                })
187                .await?;
188            Ok(())
189        })
190    }
191
192    pub fn delete_dev_server_project(
193        &mut self,
194        id: DevServerProjectId,
195        cx: &mut ModelContext<Self>,
196    ) -> Task<Result<()>> {
197        let client = self.client.clone();
198        cx.background_executor().spawn(async move {
199            client
200                .request(proto::DeleteDevServerProject {
201                    dev_server_project_id: id.0,
202                })
203                .await?;
204            Ok(())
205        })
206    }
207}