Skip to content

Commit 0f32b30

Browse files
committed
refactor(app): improve component factory and LSP server lifecycle
1 parent e90c42a commit 0f32b30

File tree

3 files changed

+63
-97
lines changed

3 files changed

+63
-97
lines changed

src/app/component_factory.rs

Lines changed: 37 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::env::VarError;
33
use bollard::Docker;
44
use serde::Deserialize;
55
use thiserror::Error;
6+
use tower_lsp::jsonrpc::{Error as LspError, ErrorCode};
67

78
use crate::infra::{DockerImageBuilder, SysdigAPIToken, SysdigImageScanner};
89

@@ -17,19 +18,14 @@ pub struct SysdigConfig {
1718
api_token: Option<SysdigAPIToken>,
1819
}
1920

20-
#[derive(Clone, Default)]
21+
#[derive(Clone)]
2122
pub struct ComponentFactory {
22-
config: Option<Config>,
23-
24-
scanner: Option<SysdigImageScanner>,
25-
builder: Option<DockerImageBuilder>,
23+
scanner: SysdigImageScanner,
24+
builder: DockerImageBuilder,
2625
}
2726

2827
#[derive(Error, Debug)]
2928
pub enum ComponentFactoryError {
30-
#[error("the configuration has not been provided")]
31-
ConfigurationNotProvided,
32-
3329
#[error("unable to retrieve sysdig api token from env var: {0}")]
3430
UnableToRetrieveAPITokenFromEnvVar(#[from] VarError),
3531

@@ -38,43 +34,48 @@ pub enum ComponentFactoryError {
3834
}
3935

4036
impl ComponentFactory {
41-
pub fn initialize_with(&mut self, config: Config) {
42-
self.config.replace(config);
43-
self.scanner.take();
44-
}
45-
46-
pub fn image_scanner(&mut self) -> Result<SysdigImageScanner, ComponentFactoryError> {
47-
if self.scanner.is_some() {
48-
return Ok(self.scanner.clone().unwrap());
49-
}
50-
51-
let Some(config) = &self.config else {
52-
return Err(ComponentFactoryError::ConfigurationNotProvided);
53-
};
54-
37+
pub fn new(config: Config) -> Result<Self, ComponentFactoryError> {
5538
let token = config
5639
.sysdig
5740
.api_token
5841
.clone()
5942
.map(Ok)
6043
.unwrap_or_else(|| std::env::var("SECURE_API_TOKEN").map(SysdigAPIToken))?;
6144

62-
let image_scanner = SysdigImageScanner::new(config.sysdig.api_url.clone(), token);
45+
let scanner = SysdigImageScanner::new(config.sysdig.api_url.clone(), token);
6346

64-
self.scanner.replace(image_scanner);
65-
Ok(self.scanner.clone().unwrap())
47+
let docker_client = Docker::connect_with_local_defaults()?;
48+
let builder = DockerImageBuilder::new(docker_client);
49+
50+
Ok(Self { scanner, builder })
6651
}
6752

68-
pub fn image_builder(&mut self) -> Result<DockerImageBuilder, ComponentFactoryError> {
69-
if self.builder.is_some() {
70-
return Ok(self.builder.clone().unwrap());
71-
}
53+
pub fn image_scanner(&self) -> &SysdigImageScanner {
54+
&self.scanner
55+
}
7256

73-
let docker_client = Docker::connect_with_local_defaults()?;
74-
let image_builder = DockerImageBuilder::new(docker_client);
57+
pub fn image_builder(&self) -> &DockerImageBuilder {
58+
&self.builder
59+
}
60+
}
7561

76-
self.builder.replace(image_builder);
77-
Ok(self.builder.clone().unwrap())
62+
impl From<ComponentFactoryError> for LspError {
63+
fn from(err: ComponentFactoryError) -> Self {
64+
let (code, message) = match err {
65+
ComponentFactoryError::UnableToRetrieveAPITokenFromEnvVar(e) => (
66+
ErrorCode::InternalError,
67+
format!("Could not read SECURE_API_TOKEN from environment: {}", e),
68+
),
69+
ComponentFactoryError::DockerClientError(e) => (
70+
ErrorCode::InternalError,
71+
format!("Failed to connect to Docker: {}", e),
72+
),
73+
};
74+
LspError {
75+
code,
76+
message: message.into(),
77+
data: None,
78+
}
7879
}
7980
}
8081

@@ -83,32 +84,8 @@ mod test {
8384
use super::{ComponentFactory, Config};
8485

8586
#[test]
86-
fn it_loads_the_factory_uninit() {
87-
let factory = ComponentFactory::default();
88-
89-
assert!(factory.config.is_none());
90-
}
91-
92-
#[test]
93-
fn it_fails_to_create_the_scanner_without_config() {
94-
let mut factory = ComponentFactory::default();
95-
96-
assert!(factory.image_scanner().is_err());
97-
}
98-
99-
#[test]
100-
fn it_creates_a_scanner_after_initializing() {
101-
let mut factory = ComponentFactory::default();
102-
103-
factory.initialize_with(Config::default());
104-
105-
assert!(factory.image_scanner().is_ok());
106-
}
107-
108-
#[test]
109-
fn it_creates_a_builder_without_config() {
110-
let mut factory = ComponentFactory::default();
111-
112-
assert!(factory.image_builder().is_ok());
87+
fn it_creates_a_factory() {
88+
let factory = ComponentFactory::new(Config::default());
89+
assert!(factory.is_ok());
11390
}
11491
}

src/app/lsp_server/lsp_server_inner.rs

Lines changed: 25 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,16 @@ impl<C> LSPServerInner<C>
4242
where
4343
C: LSPClient + Send + Sync + 'static,
4444
{
45-
async fn initialize_component_factory_with(&mut self, config: &Value) -> Result<()> {
46-
let Ok(config) = serde_json::from_value::<Config>(config.clone()) else {
47-
return Err(Error::internal_error()
48-
.with_message(format!("unable to transform json into config: {config}")));
49-
};
45+
fn update_component_factory(&mut self, config: &Value) -> Result<()> {
46+
let config = serde_json::from_value::<Config>(config.clone()).map_err(|e| {
47+
Error::internal_error()
48+
.with_message(format!("unable to transform json into config: {e}"))
49+
})?;
5050

5151
debug!("updating with configuration: {config:?}");
5252

53-
let mut factory = ComponentFactory::default();
54-
factory.initialize_with(config);
55-
self.component_factory = Some(factory);
53+
let factory = ComponentFactory::new(config)?;
54+
self.component_factory.replace(factory);
5655

5756
debug!("updated configuration");
5857
Ok(())
@@ -89,7 +88,7 @@ where
8988
});
9089
};
9190

92-
self.initialize_component_factory_with(&config).await?;
91+
self.update_component_factory(&config)?;
9392

9493
Ok(InitializeResult {
9594
capabilities: ServerCapabilities {
@@ -118,9 +117,7 @@ where
118117
}
119118

120119
pub async fn did_change_configuration(&mut self, params: DidChangeConfigurationParams) {
121-
let _ = self
122-
.initialize_component_factory_with(&params.settings)
123-
.await;
120+
let _ = self.update_component_factory(&params.settings);
124121
}
125122

126123
pub async fn did_open(&self, params: DidOpenTextDocumentParams) {
@@ -165,37 +162,29 @@ where
165162
Ok(Some(code_lenses))
166163
}
167164

168-
fn component_factory_mut(&mut self) -> Result<&mut ComponentFactory> {
169-
self.component_factory
170-
.as_mut()
171-
.ok_or_else(|| Error::internal_error().with_message("LSP not initialized"))
172-
}
173-
174165
async fn execute_base_image_scan(
175-
&mut self,
166+
&self,
176167
location: tower_lsp::lsp_types::Location,
177168
image: String,
178169
) -> Result<()> {
179-
let image_scanner = self.component_factory_mut()?.image_scanner().map_err(|e| {
180-
Error::internal_error().with_message(format!("unable to create image scanner: {e}"))
181-
})?;
182-
ScanBaseImageCommand::new(&image_scanner, &self.interactor, location, image)
170+
let factory = self
171+
.component_factory
172+
.as_ref()
173+
.ok_or_else(|| Error::internal_error().with_message("LSP not initialized"))?;
174+
let image_scanner = factory.image_scanner();
175+
ScanBaseImageCommand::new(image_scanner, &self.interactor, location, image)
183176
.execute()
184177
.await
185178
}
186179

187-
async fn execute_build_and_scan(
188-
&mut self,
189-
location: tower_lsp::lsp_types::Location,
190-
) -> Result<()> {
191-
let factory = self.component_factory_mut()?;
192-
let image_scanner = factory.image_scanner().map_err(|e| {
193-
Error::internal_error().with_message(format!("unable to create image scanner: {e}"))
194-
})?;
195-
let image_builder = factory.image_builder().map_err(|e| {
196-
Error::internal_error().with_message(format!("unable to create image builder: {e}"))
197-
})?;
198-
BuildAndScanCommand::new(&image_builder, &image_scanner, &self.interactor, location)
180+
async fn execute_build_and_scan(&self, location: tower_lsp::lsp_types::Location) -> Result<()> {
181+
let factory = self
182+
.component_factory
183+
.as_ref()
184+
.ok_or_else(|| Error::internal_error().with_message("LSP not initialized"))?;
185+
let image_scanner = factory.image_scanner();
186+
let image_builder = factory.image_builder();
187+
BuildAndScanCommand::new(image_builder, image_scanner, &self.interactor, location)
199188
.execute()
200189
.await
201190
}
@@ -211,7 +200,7 @@ where
211200
}
212201
}
213202

214-
pub async fn execute_command(&mut self, params: ExecuteCommandParams) -> Result<Option<Value>> {
203+
pub async fn execute_command(&self, params: ExecuteCommandParams) -> Result<Option<Value>> {
215204
let command: SupportedCommands = params.try_into()?;
216205
let command_name = command.to_string();
217206

src/app/lsp_server/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ where
8585
}
8686

8787
async fn execute_command(&self, params: ExecuteCommandParams) -> Result<Option<Value>> {
88-
self.inner.write().await.execute_command(params).await
88+
self.inner.read().await.execute_command(params).await
8989
}
9090

9191
async fn shutdown(&self) -> Result<()> {

0 commit comments

Comments
 (0)