use std::{
future::Future,
pin::Pin,
rc::Rc,
};
use crate::fetch::request_builder::{RequestBuilder, RequestBody};
use crate::{
Dependencies, DropResource, FutureBox,
Instant, WebsocketMessage, JsJson,
css::css_manager::CssManager, Context,
};
use crate::{
driver_module::api::ApiImport,
driver_module::utils::futures_spawn::spawn_local,
};
use crate::driver_module::dom::DriverDom;
use super::api::DomAccess;
#[derive(Debug, Clone, Copy)]
pub enum FetchMethod {
GET,
POST,
}
impl FetchMethod {
pub fn to_str(&self) -> String {
match self {
Self::GET => "GET",
Self::POST => "POST",
}.into()
}
}
type Executable = dyn Fn(Pin<Box<dyn Future<Output = ()> + 'static>>);
#[derive(Clone)]
pub struct DriverInner {
pub(crate) api: ApiImport,
pub(crate) dependencies: Dependencies,
pub(crate) css_manager: CssManager,
pub(crate) dom: Rc<DriverDom>,
spawn_executor: Rc<Executable>,
_subscribe: Rc<DropResource>,
}
impl DriverInner {
pub fn new() -> Self {
let dependencies = Dependencies::default();
let api = ApiImport::default();
let spawn_executor = {
let api = api.clone();
Rc::new(move |fut: Pin<Box<dyn Future<Output = ()> + 'static>>| {
spawn_local(api.clone(), fut);
})
};
let dom = Rc::new(DriverDom::new(&api));
let css_manager = {
let driver_dom = dom.clone();
CssManager::new(move |selector: &str, value: &str| {
driver_dom.insert_css(selector, value);
})
};
let subscribe = dependencies.transaction_state.hooks.on_after_transaction({
let dom = dom.clone();
move || {
dom.flush_dom_changes();
}
});
DriverInner {
api,
dependencies,
css_manager,
dom,
spawn_executor,
_subscribe: Rc::new(subscribe),
}
}
}
pub type FetchResult = Result<(u32, RequestBody), String>;
#[derive(Clone)]
pub struct Driver {
pub(crate) inner: Rc<DriverInner>,
}
impl Default for Driver {
fn default() -> Self {
let driver = Rc::new(DriverInner::new());
Driver {
inner: driver,
}
}
}
impl Driver {
pub fn cookie_get(&self, cname: &str) -> String {
self.inner.api.cookie_get(cname)
}
pub fn cookie_get_json(&self, cname: &str) -> JsJson {
self.inner.api.cookie_get_json(cname)
}
pub fn cookie_set(&self, cname: &str, cvalue: &str, expires_in: u64) {
self.inner.api.cookie_set(cname, cvalue, expires_in)
}
pub fn cookie_set_json(&self, cname: &str, cvalue: JsJson, expires_in: u64) {
self.inner.api.cookie_set_json(cname, cvalue, expires_in)
}
pub fn history_back(&self) {
self.inner.api.history_back();
}
#[must_use]
pub fn set_interval(&self, time: u32, func: impl Fn() + 'static) -> DropResource {
self.inner.api.interval_set(time, func)
}
pub fn now(&self) -> Instant {
Instant::now(self.inner.api.clone())
}
#[must_use]
pub fn request_get(&self, url: impl Into<String>) -> RequestBuilder {
RequestBuilder::get(url)
}
#[must_use]
pub fn request_post(&self, url: impl Into<String>) -> RequestBuilder {
RequestBuilder::post(url)
}
#[must_use]
pub fn sleep(&self, time: u32) -> FutureBox<()> {
let (sender, future) = FutureBox::new();
self.inner.api.set_timeout_and_detach(time, move || {
sender.publish(());
});
future
}
pub fn get_random(&self, min: u32, max: u32) -> u32 {
self.inner.api.get_random(min, max)
}
pub fn get_random_from<K: Clone>(&self, list: &[K]) -> Option<K> {
let len = list.len();
if len < 1 {
return None;
}
let max_index = len - 1;
let index = self.get_random(0, max_index as u32);
Some(list[index as usize].clone())
}
#[must_use]
pub fn websocket<F: Fn(WebsocketMessage) + 'static>(&self, host: impl Into<String>, callback: F) -> DropResource {
self.inner.api.websocket(host, callback)
}
pub fn spawn(&self, future: impl Future<Output = ()> + 'static) {
let future = Box::pin(future);
let spawn_executor = self.inner.spawn_executor.clone();
spawn_executor(future);
}
pub fn transaction<R, F: FnOnce(&Context) -> R>(&self, func: F) -> R {
self.inner.dependencies.transaction(func)
}
pub fn dom_access(&self) -> DomAccess {
self.inner.api.dom_access()
}
pub fn on_after_transaction(&self, callback: impl Fn() + 'static) -> DropResource {
self.inner.dependencies.transaction_state.hooks.on_after_transaction(callback)
}
pub fn is_browser(&self) -> bool {
self.inner.api.is_browser()
}
pub fn is_server(&self) -> bool {
!self.is_browser()
}
}