Add API version validation

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/4/head
trivernis 3 years ago
parent e54fda8f5c
commit 9b457564bb

@ -5,5 +5,8 @@ pub type ApiResult<T> = Result<T, ApiError>;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum ApiError { pub enum ApiError {
#[error(transparent)] #[error(transparent)]
IPC(#[from] rmp_ipc::error::Error) IPC(#[from] rmp_ipc::error::Error),
#[error("The servers api version is incompatible with the api client")]
VersionMismatch,
} }

@ -2,10 +2,10 @@ pub mod error;
pub mod file; pub mod file;
pub mod tag; pub mod tag;
use crate::client_api::error::ApiResult; use crate::client_api::error::{ApiError, ApiResult};
use crate::client_api::file::FileApi; use crate::client_api::file::FileApi;
use crate::client_api::tag::TagApi; use crate::client_api::tag::TagApi;
use crate::types::misc::InfoResponse; use crate::types::misc::{check_apis_compatible, get_api_version, InfoResponse};
use async_trait::async_trait; use async_trait::async_trait;
use rmp_ipc::context::{PoolGuard, PooledContext}; use rmp_ipc::context::{PoolGuard, PooledContext};
use rmp_ipc::ipc::context::Context; use rmp_ipc::ipc::context::Context;
@ -72,8 +72,15 @@ impl ApiClient {
.address(address) .address(address)
.build_pooled_client(8) .build_pooled_client(8)
.await?; .await?;
let client = Self::new(ctx);
let info = client.info().await?;
let server_api_version = info.api_version();
Ok(Self::new(ctx)) if !check_apis_compatible(get_api_version(), server_api_version) {
Err(ApiError::VersionMismatch)
} else {
Ok(client)
}
} }
/// Returns information about the connected ipc server /// Returns information about the connected ipc server

@ -40,6 +40,7 @@ impl From<ApiError> for PluginError {
format!("{:?}", e) format!("{:?}", e)
} }
}, },
ApiError::VersionMismatch => {String::from("The servers API version is not supported by the client. Please make sure both are up to date.")}
}; };
Self { message } Self { message }
} }

@ -1,7 +1,55 @@
use serde::{Serialize, Deserialize}; use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct InfoResponse { pub struct InfoResponse {
pub name: String, pub name: String,
pub version: String, pub version: String,
pub(crate) api_version: (u32, u32, u32),
}
impl InfoResponse {
/// Creates a new info response
pub fn new(name: String, version: String) -> Self {
Self {
name,
version,
api_version: get_api_version(),
}
}
/// Returns the api version of the crate
pub fn api_version(&self) -> (u32, u32, u32) {
self.api_version
}
}
/// Retrieves the api version of the crate version in numbers
pub fn get_api_version() -> (u32, u32, u32) {
let mut major = env!("CARGO_PKG_VERSION_MAJOR").to_string();
let mut minor = env!("CARGO_PKG_VERSION_MINOR").to_string();
let mut patch = env!("CARGO_PKG_VERSION_PATCH").to_string();
major.retain(char::is_numeric);
minor.retain(char::is_numeric);
patch.retain(char::is_numeric);
let major = major
.parse::<u32>()
.expect("Failed to parse major crate version");
let minor = minor
.parse::<u32>()
.expect("Failed to parse minor crate version");
let patch = patch
.parse::<u32>()
.expect("Failed to parse patch crate version");
(major, minor, patch)
}
/// Checks if the api the client consumes is compatible to the one the server provides
pub fn check_apis_compatible(
client_version: (u32, u32, u32),
server_version: (u32, u32, u32),
) -> bool {
// the major version must be the same while the client minor version can be lower than the servers
// so that the client has access to all its supported functionality
client_version.0 == server_version.0 && client_version.1 <= server_version.1
} }
Loading…
Cancel
Save