use commands_module::CommandRequest;
use tokio::sync::mpsc;
pub mod commands_module;
pub mod common;
pub mod credentials_module;
pub mod locations_module;
pub mod sessions_module;
pub mod types;
pub mod versions_module;
mod client;
mod context;
mod error;
mod party;
mod party_store;
mod sessions_store;
mod versions_store;
pub use {
client::Client,
commands_module::{CommandsModule, ResponsePromise, ResultPromise},
common::*,
context::{Context, ContextResult, IntoContextResult},
credentials_module::CredentialsModule,
error::{ClientError, Error, HubError, ServerError},
party::Party,
party_store::PartyStore,
sessions_module::SessionsModule,
sessions_store::SessionsStore,
types::*,
versions_module::VersionsModule,
versions_store::{SimpleVersionsStore, VersionsStore},
};
use std::borrow::Cow;
#[cfg(feature = "warp")]
pub mod warp {
pub use super::context::warp_extensions::*;
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(serde::Serialize)]
pub struct Response {
#[serde(skip)]
pub http_status: http::StatusCode,
#[serde(rename = "status_code")]
pub code: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<serde_json::Value>,
#[serde(rename = "status_message", skip_serializing_if = "Option::is_none")]
pub message: Option<Cow<'static, str>>,
pub timestamp: types::DateTime,
#[serde(skip)]
pub request_id: Option<String>,
#[serde(skip)]
pub correlation_id: Option<String>,
}
impl Response {
pub fn into_http<B>(self) -> http::Response<B>
where
B: From<Vec<u8>>,
{
let http_status = self.http_status;
let body = serde_json::to_vec(&self).expect("Serializing reply");
let mut b = http::Response::builder()
.status(http_status)
.header("content-type", "application/json");
if let Some(request_id) = self.request_id {
b = b.header("X-Request-ID", request_id);
}
if let Some(correlation_id) = self.correlation_id {
b = b.header("X-Correlation-ID", correlation_id);
}
b.body(body.into()).expect("Creating OCPI Response")
}
pub fn from_err(err: Error) -> Self {
Self {
http_status: err.http_status_code(),
code: err.code(),
data: None,
message: Some(Cow::Owned(err.to_string())),
timestamp: types::DateTime::now(),
request_id: None,
correlation_id: None,
}
}
}
impl<T> From<ContextResult<T>> for Response
where
T: serde::Serialize,
{
fn from(
ContextResult {
result,
context:
Context {
correlation_id,
request_id,
..
},
}: ContextResult<T>,
) -> Self {
match result {
Ok(data) => Response {
http_status: http::StatusCode::OK,
code: 1000,
data: Some(serde_json::to_value(&data).expect("Serializing data")),
message: Some(Cow::Borrowed("Success")),
timestamp: types::DateTime::now(),
request_id: Some(request_id),
correlation_id: Some(correlation_id),
},
Err(err) => Response::from_err(err),
}
}
}
impl<T> From<Result<T>> for Response
where
T: serde::Serialize,
{
fn from(res: Result<T>) -> Self {
match res {
Ok(data) => Response {
http_status: http::StatusCode::OK,
code: 1000,
data: Some(serde_json::to_value(&data).expect("Serializing response")),
message: Some(Cow::Borrowed("Success")),
timestamp: types::DateTime::now(),
request_id: None,
correlation_id: None,
},
Err(err) => Response::from_err(err),
}
}
}
impl<T> From<Result<Paginated<T>>> for Response
where
T: serde::Serialize,
{
fn from(res: Result<Paginated<T>>) -> Self {
match res {
Ok(paginated) => Response {
http_status: http::StatusCode::OK,
code: 1000,
data: Some(serde_json::to_value(&paginated.items).expect("Serializing data")),
message: Some(Cow::Borrowed("Success")),
timestamp: types::DateTime::now(),
request_id: None,
correlation_id: None,
},
Err(err) => Response::from_err(err),
}
}
}
trait CommandsHandler
where
Self: Clone + Send + Sync + 'static,
{
}
#[derive(Clone)]
pub struct MpscCommandsHandler<P>(mpsc::Sender<CommandRequest<P>>);
#[derive(Clone)]
pub struct NoCommandsHandler;
impl<P> CommandsHandler for MpscCommandsHandler<P> where P: Party {}
impl CommandsHandler for NoCommandsHandler {}
#[derive(Clone)]
pub struct Cpo<DB, CH>
where
DB: Store,
{
db: DB,
client: Client,
commands_handler: CH,
}
impl<DB> Cpo<DB, NoCommandsHandler>
where
DB: Store,
{
pub fn new(db: DB, client: Client) -> Self {
Self {
db,
client,
commands_handler: NoCommandsHandler,
}
}
}
impl<DB> Cpo<DB, NoCommandsHandler>
where
DB: Store,
{
pub fn with_mpsc_commands_handler(
self,
tx: mpsc::Sender<CommandRequest<DB::PartyModel>>,
) -> Cpo<DB, MpscCommandsHandler<DB::PartyModel>> {
Cpo {
db: self.db,
client: self.client,
commands_handler: MpscCommandsHandler(tx),
}
}
}
pub enum Authorized<P, R> {
Party(P),
Registration(R),
}
impl<P, R> Authorized<P, R>
where
P: Party,
{
pub fn party(self) -> Result<P> {
match self {
Self::Party(party) => Ok(party),
_ => Err(Error::unauthorized("Invalid Token")),
}
}
pub fn registration(self) -> Result<R> {
match self {
Self::Registration(temp) => Ok(temp),
_ => Err(Error::unauthorized("Invalid Token")),
}
}
}
#[async_trait::async_trait]
pub trait Store
where
Self: Clone + Send + Sync + 'static,
{
type PartyModel: Party;
type RegistrationModel: Send + Sync + 'static;
async fn get_authorized(
&self,
token: types::CredentialsToken,
) -> Result<Authorized<Self::PartyModel, Self::RegistrationModel>>;
}