Skip to content

Commit b48e218

Browse files
committed
Refactor codebase (#23)
- Refined some derived traits - Refactor Service/ServiceInfo: Move some trait implementations from Service to ServiceInfo and refer to the implementations from Service - Compare ID instead of name in ServiceManagerBuilder
1 parent 98498dc commit b48e218

File tree

3 files changed

+53
-39
lines changed

3 files changed

+53
-39
lines changed

src/config.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ fn discord_token_default() -> String {
3737
String::from("Please provide a token")
3838
}
3939

40-
#[derive(Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
40+
#[derive(Debug, PartialEq, PartialOrd, Serialize, Deserialize, Clone)]
4141
pub struct Config {
4242
#[serde(rename = "discordToken", default = "discord_token_default")]
4343
pub discord_token: String,
@@ -88,7 +88,7 @@ impl ConfigHandler {
8888

8989
pub fn create_config_dir_path(&self) -> Result<(), ConfigInitError> {
9090
let path = self.get_config_dir_path()?;
91-
std::fs::create_dir_all(path)?;
91+
fs::create_dir_all(path)?;
9292
Ok(())
9393
}
9494

@@ -112,7 +112,7 @@ impl ConfigHandler {
112112
Ok(())
113113
}
114114

115-
pub fn get_config(&self) -> Result<Config, ConfigParseError> {
115+
pub fn load_config(&self) -> Result<Config, ConfigParseError> {
116116
let path = self.get_config_file_path()?;
117117
if !path.exists() {
118118
self.create_config_dir_path()?;

src/main.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
use ::log::{error, warn};
2-
use lum::{
3-
bot::Bot,
4-
config::{Config, ConfigHandler, ConfigParseError},
5-
log,
6-
service::Service,
7-
};
2+
use lum::{bot::Bot, config::ConfigHandler, log, service::Service};
83

94
const BOT_NAME: &str = "Lum";
105

@@ -16,7 +11,8 @@ async fn main() {
1611
warn!("THIS IS A DEBUG RELEASE!");
1712
}
1813

19-
let _config = match get_config() {
14+
let config_handler = ConfigHandler::new(BOT_NAME.to_lowercase().as_str());
15+
let _config = match config_handler.load_config() {
2016
Ok(config) => config,
2117
Err(err) => {
2218
error!(
@@ -44,11 +40,6 @@ fn setup_logger() {
4440
}
4541
}
4642

47-
fn get_config() -> Result<Config, ConfigParseError> {
48-
let config_handler = ConfigHandler::new(BOT_NAME.to_lowercase().as_str());
49-
config_handler.get_config()
50-
}
51-
5243
fn initialize_services() -> Vec<Box<dyn Service>> {
5344
//TODO: Add services
5445
//...

src/service.rs

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ use std::{
1111
};
1212
use tokio::sync::Mutex;
1313

14+
pub type PinnedBoxedFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
15+
16+
pub type PinnedBoxedFutureResult<'a, T> =
17+
PinnedBoxedFuture<'a, Result<T, Box<dyn Error + Send + Sync>>>;
18+
1419
#[derive(Debug)]
1520
pub enum Status {
1621
Started,
@@ -102,24 +107,52 @@ impl ServiceInfo {
102107
}
103108
}
104109

110+
pub fn is_available(&self) -> Pin<Box<dyn Future<Output = bool> + '_>> {
111+
Box::pin(async move {
112+
let lock = self.status.lock().await;
113+
matches!(&*lock, Status::Started)
114+
})
115+
}
116+
105117
pub async fn set_status(&self, status: Status) {
106118
let mut lock = self.status.lock().await;
107119
*lock = status;
108120
}
109121
}
110122

111-
pub type PinnedBoxedFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
123+
impl PartialEq for ServiceInfo {
124+
fn eq(&self, other: &Self) -> bool {
125+
self.id == other.id
126+
}
127+
}
112128

113-
pub type PinnedBoxedFutureResult<'a, T> =
114-
PinnedBoxedFuture<'a, Result<T, Box<dyn Error + Send + Sync>>>;
129+
impl Eq for ServiceInfo {}
115130

116-
//TODO: When Rust allows async trait methods to be object-safe, refactor this to use async instead of returning a future
131+
impl Ord for ServiceInfo {
132+
fn cmp(&self, other: &Self) -> Ordering {
133+
self.name.cmp(&other.name)
134+
}
135+
}
136+
137+
impl PartialOrd for ServiceInfo {
138+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
139+
Some(self.cmp(other))
140+
}
141+
}
142+
143+
impl Hash for ServiceInfo {
144+
fn hash<H: Hasher>(&self, state: &mut H) {
145+
self.id.hash(state);
146+
}
147+
}
148+
149+
//TODO: When Rust allows async trait methods to be object-safe, refactor this to use async instead of returning a PinnedBoxedFutureResult
117150
pub trait ServiceInternals {
118151
fn start(&mut self) -> PinnedBoxedFutureResult<'_, ()>;
119152
fn stop(&mut self) -> PinnedBoxedFutureResult<'_, ()>;
120153
}
121154

122-
//TODO: When Rust allows async trait methods to be object-safe, refactor this to use async instead of returning a future
155+
//TODO: When Rust allows async trait methods to be object-safe, refactor this to use async instead of returning a PinnedBoxedFutureResult
123156
pub trait Service: ServiceInternals {
124157
fn info(&self) -> &ServiceInfo;
125158

@@ -171,33 +204,28 @@ pub trait Service: ServiceInternals {
171204
match ServiceInternals::stop(self).await {
172205
Ok(()) => {
173206
self.info().set_status(Status::Stopped).await;
207+
info!("Stopped service: {}", self.info().name);
174208
}
175209
Err(error) => {
176210
self.info().set_status(Status::FailedStopping(error)).await;
211+
error!("Failed to stop service: {}", self.info().name);
177212
}
178213
}
179214
})
180215
}
181-
182-
fn is_available(&self) -> Pin<Box<dyn Future<Output = bool> + '_>> {
183-
Box::pin(async move {
184-
let lock = self.info().status.lock().await;
185-
matches!(&*lock, Status::Started)
186-
})
187-
}
188216
}
189217

190218
impl Eq for dyn Service {}
191219

192220
impl PartialEq for dyn Service {
193221
fn eq(&self, other: &Self) -> bool {
194-
self.info().name == other.info().name
222+
self.info() == other.info()
195223
}
196224
}
197225

198226
impl Ord for dyn Service {
199227
fn cmp(&self, other: &Self) -> Ordering {
200-
self.info().name.cmp(&other.info().name)
228+
self.info().cmp(other.info())
201229
}
202230
}
203231

@@ -209,7 +237,7 @@ impl PartialOrd for dyn Service {
209237

210238
impl Hash for dyn Service {
211239
fn hash<H: Hasher>(&self, state: &mut H) {
212-
self.info().name.hash(state);
240+
self.info().hash(state);
213241
}
214242
}
215243

@@ -224,15 +252,12 @@ impl ServiceManagerBuilder {
224252
}
225253

226254
pub fn with_service(mut self, service: Box<dyn Service>) -> Self {
227-
let service_exists = self
228-
.services
229-
.iter()
230-
.any(|s| s.info().name == service.info().name); // Can't use *s == service here because value would be moved
255+
let service_exists = self.services.iter().any(|s| s.info() == service.info());
231256

232257
if service_exists {
233258
warn!(
234-
"Tried to add service {} multiple times. Ignoring.",
235-
service.info().name
259+
"Tried to add service {} ({}), but a service with that ID already exists. Ignoring.",
260+
service.info().name, service.info().id
236261
);
237262

238263
return self;
@@ -260,7 +285,6 @@ impl ServiceManager {
260285
pub fn start_services(&mut self) -> PinnedBoxedFuture<'_, ()> {
261286
Box::pin(async move {
262287
for service in &mut self.services {
263-
info!("Starting service: {}", service.info().name);
264288
service.wrapped_start().await;
265289
}
266290
})
@@ -269,7 +293,6 @@ impl ServiceManager {
269293
pub fn stop_services(&mut self) -> PinnedBoxedFuture<'_, ()> {
270294
Box::pin(async move {
271295
for service in &mut self.services {
272-
info!("Stopping service: {}", service.info().name);
273296
service.wrapped_stop().await;
274297
}
275298
})
@@ -423,7 +446,7 @@ impl Display for ServiceManager {
423446

424447
let mut services = self.services.iter().peekable();
425448
while let Some(service) = services.next() {
426-
write!(f, "{}", service.info().name)?;
449+
write!(f, "{} ({})", service.info().name, service.info().id)?;
427450
if services.peek().is_some() {
428451
write!(f, ", ")?;
429452
}

0 commit comments

Comments
 (0)