use crate::error::{PostDataError, SessionSendError};
use crate::transport::ConnectionTransport;
use crate::{BidiSession, CommandResponseState};
use form_urlencoded;
use rustenium_bidi_definitions::Command;
use rustenium_bidi_definitions::network::command_builders::{
ContinueRequestBuilder, ContinueWithAuthBuilder, FailRequestBuilder, ProvideResponseBuilder
};
use rustenium_bidi_definitions::network::events::{AuthRequiredParams, BeforeRequestSentParams
};
use rustenium_bidi_definitions::network::type_builders::{ContinueWithAuthCredentialsBuilder, ContinueWithAuthNoCredentialsBuilder};
use rustenium_bidi_definitions::network::types::{AuthCredentials, BaseParameters, ContinueWithAuthCredentialsAction, ContinueWithAuthCredentialsContinueWithAuthNoCredentialsUnion, ContinueWithAuthNoCredentialsAction, Header, Request};
use tokio::sync::oneshot;
#[derive(Debug, Clone)]
pub enum NetworkRequestHandledState {
Continued,
Aborted,
Responded,
}
use serde_json;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::Mutex;
pub struct NetworkRequest<T: ConnectionTransport> {
pub base: BaseParameters,
session: Arc<Mutex<BidiSession<T>>>,
}
impl<T: ConnectionTransport> std::fmt::Debug for NetworkRequest<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("NetworkRequest")
.field("base", &self.base)
.field("session", &"<Arc<Mutex<Session>>>")
.finish()
}
}
impl<T: ConnectionTransport> NetworkRequest<T> {
pub fn new(params: BeforeRequestSentParams, session: Arc<Mutex<BidiSession<T>>>) -> Self {
NetworkRequest {
base: params.base_parameters,
session,
}
}
pub fn from_auth_required(params: AuthRequiredParams, session: Arc<Mutex<BidiSession<T>>>) -> Self {
NetworkRequest {
base: params.base_parameters,
session,
}
}
pub fn request_id(&self) -> &Request {
&self.base.request.request
}
pub fn url(&self) -> &str {
&self.base.request.url
}
pub fn headers(&self) -> &Vec<Header> {
&self.base.request.headers
}
pub fn method(&self) -> &str {
&self.base.request.method
}
pub fn has_post_data(&self) -> bool {
self.base
.request
.extensible
.get("goog:hasPostData")
.and_then(|v| v.as_bool())
.unwrap_or(false)
}
pub fn post_data(&self) -> Option<&str> {
self.base
.request
.extensible
.get("goog:postData")
.and_then(|v| v.as_str())
}
pub fn post_data_json(
&self,
) -> Result<serde_json::Map<String, serde_json::Value>, PostDataError> {
let data = self.post_data().ok_or(PostDataError::NoPostData)?;
let value: serde_json::Value = serde_json::from_str(data)?;
value
.as_object()
.cloned()
.ok_or(PostDataError::NotJsonObject)
}
pub fn post_data_form(&self) -> Result<HashMap<String, String>, PostDataError> {
let data = self.post_data().ok_or(PostDataError::NoPostData)?;
let parsed: HashMap<String, String> = form_urlencoded::parse(data.as_bytes())
.into_owned()
.collect();
Ok(parsed)
}
pub async fn is_handled(&self) -> bool {
self.session
.lock()
.await
.handled_network_requests
.lock()
.unwrap()
.contains_key(self.request_id().as_ref())
}
pub async fn get_handled_state(&self) -> Option<NetworkRequestHandledState> {
self.session
.lock()
.await
.handled_network_requests
.lock()
.unwrap()
.get(self.request_id().as_ref())
.cloned()
}
async fn mark_handled(&self, state: NetworkRequestHandledState) {
let session = self.session.lock().await;
session
.handled_network_requests
.lock()
.unwrap()
.insert(self.base.request.request.clone().into(), state);
}
pub async fn continue_(&self) -> oneshot::Receiver<CommandResponseState> {
let command: Command = ContinueRequestBuilder::default()
.request(self.base.request.request.clone())
.build()
.unwrap()
.into();
let rx = self
.session
.lock()
.await
.send_and_get_receiver(command)
.await;
self.mark_handled(NetworkRequestHandledState::Continued)
.await;
rx
}
pub async fn continue_with(
&self,
continue_request: ContinueRequestBuilder,
) -> oneshot::Receiver<CommandResponseState> {
let continue_request = continue_request.request(self.base.request.request.clone()).build().unwrap();
let rx = self
.session
.lock()
.await
.send_and_get_receiver(continue_request)
.await;
self.mark_handled(NetworkRequestHandledState::Continued)
.await;
rx
}
pub async fn abort(&self) -> oneshot::Receiver<CommandResponseState> {
let command = FailRequestBuilder::default()
.request(self.base.request.request.clone())
.build().unwrap();
let rx = self
.session
.lock()
.await
.send_and_get_receiver(command)
.await;
self.mark_handled(NetworkRequestHandledState::Aborted).await;
rx
}
pub async fn respond(
&self,
provide_response_builder: ProvideResponseBuilder
) -> oneshot::Receiver<CommandResponseState> {
let command = provide_response_builder.request(self.request_id().clone()).build().unwrap();
let rx = self
.session
.lock()
.await
.send_and_get_receiver(command)
.await;
self.mark_handled(NetworkRequestHandledState::Responded)
.await;
rx
}
pub async fn continue_with_auth(
&self,
credentials: AuthCredentials,
) -> Result<(), SessionSendError> {
let command =
ContinueWithAuthBuilder::default().continue_with_auth_credentials_continue_with_auth_no_credentials_union(ContinueWithAuthCredentialsContinueWithAuthNoCredentialsUnion::ContinueWithAuthCredentials(
ContinueWithAuthCredentialsBuilder::default().action(ContinueWithAuthCredentialsAction::ProvideCredentials).credentials(
credentials).build().unwrap())).request(self.request_id().clone()).build().unwrap();
self.session.lock().await.send(command).await.map(|_| ())
}
pub async fn continue_with_no_auth(&self, action: ContinueWithAuthNoCredentialsAction) -> Result<(), SessionSendError> {
let command = ContinueWithAuthBuilder::default().continue_with_auth_credentials_continue_with_auth_no_credentials_union(ContinueWithAuthCredentialsContinueWithAuthNoCredentialsUnion::ContinueWithAuthNoCredentials(
ContinueWithAuthNoCredentialsBuilder::default().action(action).build().unwrap()
)).request(self.request_id().clone()).build().unwrap();
self.session.lock().await.send(command).await.map(|_| ())
}
}