-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Simplify server errors and drop some unused code #1095
Changes from all commits
f3babaf
f72393e
c4878b8
f2848d0
80ac668
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,40 +9,25 @@ use crate::{ | |
use agama_locale_data::{InvalidKeymap, LocaleId}; | ||
use axum::{ | ||
extract::State, | ||
http::StatusCode, | ||
response::{IntoResponse, Response}, | ||
routing::{get, put}, | ||
Json, Router, | ||
}; | ||
use serde::{Deserialize, Serialize}; | ||
use serde_json::json; | ||
use std::{ | ||
process::Command, | ||
sync::{Arc, RwLock}, | ||
}; | ||
use thiserror::Error; | ||
|
||
#[derive(Error, Debug)] | ||
#[derive(thiserror::Error, Debug)] | ||
pub enum LocaleError { | ||
#[error("Unknown locale code: {0}")] | ||
UnknownLocale(String), | ||
#[error("Unknown timezone: {0}")] | ||
UnknownTimezone(String), | ||
#[error("Invalid keymap: {0}")] | ||
InvalidKeymap(#[from] InvalidKeymap), | ||
#[error("Cannot translate: {0}")] | ||
OtherError(#[from] Error), | ||
#[error("Cannot change the local keymap: {0}")] | ||
CouldNotSetKeymap(#[from] std::io::Error), | ||
} | ||
|
||
impl IntoResponse for LocaleError { | ||
fn into_response(self) -> Response { | ||
let body = json!({ | ||
"error": self.to_string() | ||
}); | ||
(StatusCode::BAD_REQUEST, Json(body)).into_response() | ||
} | ||
#[error("Could not apply the changes")] | ||
Commit(#[from] std::io::Error), | ||
} | ||
|
||
#[derive(Clone)] | ||
|
@@ -119,14 +104,14 @@ async fn keymaps(State(state): State<LocaleState>) -> Json<Vec<Keymap>> { | |
async fn set_config( | ||
State(state): State<LocaleState>, | ||
Json(value): Json<LocaleConfig>, | ||
) -> Result<Json<()>, LocaleError> { | ||
) -> Result<Json<()>, Error> { | ||
let mut data = state.locale.write().unwrap(); | ||
let mut changes = LocaleConfig::default(); | ||
|
||
if let Some(locales) = &value.locales { | ||
for loc in locales { | ||
if !data.locales_db.exists(loc.as_str()) { | ||
return Err(LocaleError::UnknownLocale(loc.to_string())); | ||
return Err(LocaleError::UnknownLocale(loc.to_string()))?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why it needs There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because it returns a |
||
} | ||
} | ||
data.locales = locales.clone(); | ||
|
@@ -135,14 +120,14 @@ async fn set_config( | |
|
||
if let Some(timezone) = &value.timezone { | ||
if !data.timezones_db.exists(timezone) { | ||
return Err(LocaleError::UnknownTimezone(timezone.to_string())); | ||
return Err(LocaleError::UnknownTimezone(timezone.to_string()))?; | ||
} | ||
data.timezone = timezone.to_owned(); | ||
changes.timezone = Some(data.timezone.clone()); | ||
} | ||
|
||
if let Some(keymap_id) = &value.keymap { | ||
data.keymap = keymap_id.parse()?; | ||
data.keymap = keymap_id.parse().map_err(LocaleError::InvalidKeymap)?; | ||
changes.keymap = Some(keymap_id.clone()); | ||
} | ||
|
||
|
@@ -161,14 +146,17 @@ async fn set_config( | |
} | ||
|
||
if let Some(ui_keymap) = &value.ui_keymap { | ||
data.ui_keymap = ui_keymap.parse()?; | ||
// data.ui_keymap = ui_keymap.parse().into::<Result<KeymapId, LocaleError>>()?; | ||
data.ui_keymap = ui_keymap.parse().map_err(LocaleError::InvalidKeymap)?; | ||
Command::new("/usr/bin/localectl") | ||
.args(["set-x11-keymap", &ui_keymap]) | ||
.output()?; | ||
.output() | ||
.map_err(LocaleError::Commit)?; | ||
Command::new("/usr/bin/setxkbmap") | ||
.arg(&ui_keymap) | ||
.env("DISPLAY", ":0") | ||
.output()?; | ||
.output() | ||
.map_err(LocaleError::Commit)?; | ||
} | ||
|
||
_ = state.events.send(Event::L10nConfigChanged(changes)); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
generic comment for whole this PR.
Error
only when it can return more types of error.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The advantage of using the same error is that you only need to implement the
IntoResponse
trait once. Initially, I called itApiError
, but in the end, I decided to use a single type.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
However, if you prefer, I could keep the
LocaleError
and implementIntoResponse
only for that kind. It looks good to me too.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you cannot have IntoResponse for whole Enum? If it is implemented for Error, I kind of expect it can process also element of Enum.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or maybe some kind of trait can help there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is implemented for the whole enum (the crate::error::Error) and that's the reason I am returning
Error
instead ofLocaleError
. After all,LocaleError
knows nothing aboutError
.Adding any trait is overcomplicating things, in my opinion. So I would go for:
Error
) or...LocaleError
and implementingIntoResponse
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, reason why I do not like it is because now it really see only use case for respond, but if it will be used in other parts of rust, then user of this function needs to handle any generic error, while we know that it can product only LocaleError.
So how I do see it is, that if we want to keep extensibility and allow in future to other types of Error in this function, lets change it to Error. But if we know that we always produce only LocaleError ( which I kind of expect ), then I prefer to return minimal abstraction it uses.
But ( and it is big BUT ) I do not care much in web functions that is short and really serve only as connection to real code and do some error translation. But this specific function is quite big and I would say many of its part is not web specific. So maybe if it lives elsewhere and this web function just call other method and translate its errortype into Error. Then it would much nicer.
And to conclude it, I still see this PR as improvement, so feel free to merge it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I fully agree, this code does not belong here but it is a step in the right direction.
I have added a note to this Trello card so it can be addressed later.