mirror of
https://github.com/YGGverse/Yoda.git
synced 2026-04-01 00:55:28 +00:00
begin multi-driver page client implementation
This commit is contained in:
parent
df8dea9534
commit
0c08a0fb2f
39 changed files with 741 additions and 1712 deletions
146
src/app/browser/window/tab/item/client.rs
Normal file
146
src/app/browser/window/tab/item/client.rs
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
mod driver;
|
||||
mod feature;
|
||||
|
||||
use super::Page;
|
||||
use driver::Driver;
|
||||
use feature::Feature;
|
||||
use gtk::{
|
||||
gio::Cancellable,
|
||||
glib::{Uri, UriFlags},
|
||||
prelude::CancellableExt,
|
||||
};
|
||||
use std::{cell::Cell, rc::Rc};
|
||||
|
||||
/// Multi-protocol client API for tab `Item`
|
||||
pub struct Client {
|
||||
cancellable: Cell<Cancellable>,
|
||||
driver: Rc<Driver>,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
// Constructors
|
||||
|
||||
/// Create new `Self`
|
||||
pub fn init(page: &Rc<Page>) -> Self {
|
||||
Self {
|
||||
cancellable: Cell::new(Cancellable::new()),
|
||||
driver: Rc::new(Driver::build(page)),
|
||||
}
|
||||
}
|
||||
|
||||
// Actions
|
||||
|
||||
/// Route tab item `request` to protocol driver
|
||||
/// * or `navigation` entry if the value not provided
|
||||
pub fn handle(&self, request: &str, is_snap_history: bool) {
|
||||
// run async resolver to detect Uri, scheme-less host, or search query
|
||||
lookup(
|
||||
request,
|
||||
self.driver.clone(),
|
||||
self.cancellable(),
|
||||
move |driver, feature, cancellable, uri| {
|
||||
route(driver, feature, cancellable, uri, is_snap_history)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Get new [Cancellable](https://docs.gtk.org/gio/class.Cancellable.html) by cancel previous one
|
||||
fn cancellable(&self) -> Cancellable {
|
||||
// Init new Cancellable
|
||||
let cancellable = Cancellable::new();
|
||||
|
||||
// Replace by cancel previous operations
|
||||
let previous = self.cancellable.replace(cancellable.clone());
|
||||
if !previous.is_cancelled() {
|
||||
previous.cancel();
|
||||
}
|
||||
|
||||
// Done
|
||||
cancellable
|
||||
}
|
||||
}
|
||||
|
||||
/// Create request using async DNS resolver (slow method)
|
||||
/// * useful for scheme-less requests, before apply search redirect
|
||||
/// * the `query` should not contain `feature` prefix
|
||||
fn lookup(
|
||||
query: &str,
|
||||
driver: Rc<Driver>,
|
||||
cancellable: Cancellable,
|
||||
callback: impl FnOnce(Rc<Driver>, Feature, Cancellable, Uri) + 'static,
|
||||
) {
|
||||
use gtk::{
|
||||
gio::{NetworkAddress, Resolver},
|
||||
prelude::{NetworkAddressExt, ResolverExt},
|
||||
};
|
||||
|
||||
const DEFAULT_SCHEME: &str = "gemini";
|
||||
const DEFAULT_PORT: u16 = 1965;
|
||||
const TIMEOUT: u32 = 250; // ms
|
||||
|
||||
let (feature, query) = Feature::parse(query.trim());
|
||||
|
||||
match Uri::parse(query, UriFlags::NONE) {
|
||||
Ok(uri) => callback(driver, feature, cancellable, uri),
|
||||
Err(_) => {
|
||||
// try default scheme suggestion
|
||||
let suggestion = format!("{DEFAULT_SCHEME}://{query}");
|
||||
|
||||
let resolver = Resolver::default();
|
||||
resolver.set_timeout(TIMEOUT);
|
||||
|
||||
match NetworkAddress::parse_uri(&suggestion, DEFAULT_PORT) {
|
||||
Ok(connectable) => resolver.lookup_by_name_async(
|
||||
&connectable.hostname(),
|
||||
Some(&cancellable.clone()),
|
||||
move |resolve| {
|
||||
callback(
|
||||
driver,
|
||||
feature,
|
||||
cancellable,
|
||||
if resolve.is_ok() {
|
||||
match Uri::parse(&suggestion, UriFlags::NONE) {
|
||||
Ok(uri) => uri,
|
||||
Err(_) => search(&suggestion),
|
||||
}
|
||||
} else {
|
||||
search(&suggestion)
|
||||
},
|
||||
)
|
||||
},
|
||||
),
|
||||
Err(_) => callback(driver, feature, cancellable, search(&suggestion)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Route request (resolved by `lookup` function)
|
||||
fn route(
|
||||
driver: Rc<Driver>,
|
||||
feature: Feature,
|
||||
cancellable: Cancellable,
|
||||
uri: Uri,
|
||||
is_snap_history: bool,
|
||||
) {
|
||||
match uri.scheme().as_str() {
|
||||
"gemini" => driver
|
||||
.gemini
|
||||
.handle(uri, feature, cancellable, is_snap_history),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert `query` to default search provider [Uri](https://docs.gtk.org/glib/struct.Uri.html)
|
||||
fn search(query: &str) -> Uri {
|
||||
Uri::build(
|
||||
UriFlags::NONE,
|
||||
"gemini",
|
||||
None,
|
||||
Some("tlgs.one"),
|
||||
-1,
|
||||
"/search",
|
||||
Some(&Uri::escape_string(query, None, false)),
|
||||
None,
|
||||
) // @TODO optional settings
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue