mod error; mod feature; mod gemini; mod search; use super::{Client, Response}; pub use error::Error; use feature::Feature; use gtk::{ gio::Cancellable, glib::{Uri, UriFlags}, }; /// Single `Request` API for multiple `Client` drivers pub enum Request { Gemini { feature: Feature, referrer: Option>, uri: Uri, }, Titan { referrer: Option>, uri: Uri, }, } impl Request { // Constructors /// Create new `Self` from featured string pub fn parse(query: &str, referrer: Option) -> Result { let (feature, request) = Feature::parse(query); match Uri::parse(request, UriFlags::NONE) { Ok(uri) => Self::from_uri(uri, Some(feature), referrer), Err(e) => Err(Error::Glib(e)), } } /// Create new `Self` from [Uri](https://docs.gtk.org/glib/struct.Uri.html) pub fn from_uri( uri: Uri, feature: Option, referrer: Option, ) -> Result { match uri.scheme().as_str() { "gemini" => Ok(Self::Gemini { feature: feature.unwrap_or_default(), referrer: referrer.map(Box::new), uri, }), // @TODO validate request len by constructor "titan" => Ok(Self::Titan { referrer: referrer.map(Box::new), uri, }), _ => Err(Error::Unsupported), } } // Actions /// Handle `Self` request pub fn handle( self, client: &Client, cancellable: Cancellable, callback: impl FnOnce(Response) + 'static, ) { match &self { Self::Gemini { .. } => gemini::request(client, self, cancellable, callback), Self::Titan { .. } => todo!(), } } // Getters /// Get reference to `Self` [Uri](https://docs.gtk.org/glib/struct.Uri.html) pub fn as_uri(&self) -> &Uri { match self { Self::Gemini { feature: _, referrer: _, uri, } | Self::Titan { referrer: _, uri } => uri, } } /// Get `Feature` reference for `Self` pub fn feature(&self) -> &Feature { match self { Request::Gemini { feature, .. } => feature, Request::Titan { .. } => &Feature::Default, } } /// Recursively count referrers of `Self` /// * useful to apply redirection rules by protocol driver selected pub fn referrers(&self) -> usize { let count = match self { Request::Gemini { referrer, .. } => referrer, Request::Titan { referrer, .. } => referrer, } .as_ref() .map_or(0, |request| request.referrers()); 1 + count } } // Tools /// Create new search `Request` /// @TODO // * implement DNS lookup before apply this option // * make search provider optional // * validate request len by gemini specifications pub fn search(query: &str) -> Request { Request::from_uri(search::tgls(query), None, None).unwrap() // no handler as unexpected }