mirror of
https://github.com/YGGverse/Yoda.git
synced 2025-01-15 09:10:08 +00:00
draft ggemini 0.11.0 version api
This commit is contained in:
parent
5152d915d1
commit
88a37c545b
@ -17,7 +17,7 @@ features = ["v1_6"]
|
||||
|
||||
[dependencies.gemini]
|
||||
package = "ggemini"
|
||||
version = "0.10.0"
|
||||
version = "0.11.0"
|
||||
|
||||
[dependencies.gemtext]
|
||||
package = "ggemtext"
|
||||
|
@ -135,10 +135,10 @@ impl Tab {
|
||||
// Register dynamically created tab components in the HashMap index
|
||||
self.index
|
||||
.borrow_mut()
|
||||
.insert(item.id().clone(), item.clone());
|
||||
.insert(item.id.clone(), item.clone());
|
||||
|
||||
item.page()
|
||||
.navigation()
|
||||
item.page
|
||||
.navigation
|
||||
.request()
|
||||
.widget()
|
||||
.gobject()
|
||||
@ -163,7 +163,7 @@ impl Tab {
|
||||
if let Some(page) = self.widget.page(page_position) {
|
||||
if let Some(id) = page.keyword() {
|
||||
if let Some(item) = self.index.borrow().get(&id) {
|
||||
return match item.page().bookmark() {
|
||||
return match item.page.bookmark() {
|
||||
Ok(result) => Ok(result),
|
||||
Err(_) => Err(Error::Bookmark),
|
||||
};
|
||||
@ -182,7 +182,7 @@ impl Tab {
|
||||
if let Some(page) = self.widget.page(page_position) {
|
||||
if let Some(id) = page.keyword() {
|
||||
if let Some(item) = self.index.borrow().get(&id) {
|
||||
item.page().home();
|
||||
item.page.home();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -192,7 +192,7 @@ impl Tab {
|
||||
if let Some(page) = self.widget.page(page_position) {
|
||||
if let Some(id) = page.keyword() {
|
||||
if let Some(item) = self.index.borrow().get(&id) {
|
||||
item.page().history_back();
|
||||
item.page.history_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -202,7 +202,7 @@ impl Tab {
|
||||
if let Some(page) = self.widget.page(page_position) {
|
||||
if let Some(id) = page.keyword() {
|
||||
if let Some(item) = self.index.borrow().get(&id) {
|
||||
item.page().history_forward();
|
||||
item.page.history_forward();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -213,7 +213,7 @@ impl Tab {
|
||||
if let Some(page) = self.widget.page(page_position) {
|
||||
if let Some(id) = page.keyword() {
|
||||
if let Some(item) = self.index.borrow().get(&id) {
|
||||
item.page().reload();
|
||||
item.page.reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -231,10 +231,10 @@ impl Tab {
|
||||
item.update();
|
||||
|
||||
// Update tab title on loading indicator inactive
|
||||
if !item.page().is_loading() {
|
||||
item.widget()
|
||||
if !item.page.is_loading() {
|
||||
item.widget
|
||||
.gobject()
|
||||
.set_title(item.page().meta().title().as_str())
|
||||
.set_title(item.page.meta.title().as_str())
|
||||
}
|
||||
}
|
||||
// Update all tabs on ID not found @TODO change initial update method
|
||||
@ -244,10 +244,10 @@ impl Tab {
|
||||
item.update();
|
||||
|
||||
// Update tab title on loading indicator inactive
|
||||
if !item.page().is_loading() {
|
||||
item.widget()
|
||||
if !item.page.is_loading() {
|
||||
item.widget
|
||||
.gobject()
|
||||
.set_title(item.page().meta().title().as_str())
|
||||
.set_title(item.page.meta.title().as_str())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -299,7 +299,7 @@ impl Tab {
|
||||
// Register dynamically created tab item in the HashMap index
|
||||
self.index
|
||||
.borrow_mut()
|
||||
.insert(item.id().clone(), item.clone());
|
||||
.insert(item.id.clone(), item.clone());
|
||||
}
|
||||
}
|
||||
Err(e) => return Err(e.to_string()),
|
||||
@ -327,10 +327,10 @@ impl Tab {
|
||||
item.save(
|
||||
transaction,
|
||||
&id,
|
||||
&self.widget.gobject().page_position(item.widget().gobject()),
|
||||
&item.widget().gobject().is_pinned(),
|
||||
&item.widget().gobject().is_selected(),
|
||||
&item.widget().gobject().needs_attention(),
|
||||
&self.widget.gobject().page_position(item.widget.gobject()),
|
||||
&item.widget.gobject().is_pinned(),
|
||||
&item.widget.gobject().is_selected(),
|
||||
&item.widget.gobject().needs_attention(),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
@ -24,10 +24,10 @@ use std::rc::Rc;
|
||||
pub struct Item {
|
||||
// Auto-generated unique item ID
|
||||
// useful as widget name in GTK actions callback
|
||||
id: GString,
|
||||
pub id: GString,
|
||||
// Components
|
||||
page: Rc<Page>,
|
||||
widget: Rc<Widget>,
|
||||
pub page: Rc<Page>,
|
||||
pub widget: Rc<Widget>,
|
||||
}
|
||||
|
||||
impl Item {
|
||||
@ -57,7 +57,7 @@ impl Item {
|
||||
let widget = Rc::new(Widget::new(
|
||||
id.as_str(),
|
||||
tab_view,
|
||||
page.widget().gobject(),
|
||||
page.widget.gobject(),
|
||||
None,
|
||||
position,
|
||||
(is_pinned, is_selected, is_attention),
|
||||
@ -66,11 +66,7 @@ impl Item {
|
||||
// Init events
|
||||
|
||||
if let Some(text) = request {
|
||||
page.navigation()
|
||||
.request()
|
||||
.widget()
|
||||
.gobject()
|
||||
.set_text(&text);
|
||||
page.navigation.request().widget().gobject().set_text(&text);
|
||||
|
||||
if is_load {
|
||||
page.load(true);
|
||||
@ -83,7 +79,7 @@ impl Item {
|
||||
let parent = tab_view.clone().upcast::<gtk::Widget>();
|
||||
move || {
|
||||
// Request should match valid URI for all drivers supported
|
||||
if let Some(uri) = page.navigation().request().uri() {
|
||||
if let Some(uri) = page.navigation.request().uri() {
|
||||
// Rout by scheme
|
||||
if uri.scheme().to_lowercase() == "gemini" {
|
||||
return identity::new_gemini(profile.clone(), actions.1.clone(), uri)
|
||||
@ -100,11 +96,7 @@ impl Item {
|
||||
let page = page.clone();
|
||||
move |request, is_history| {
|
||||
if let Some(text) = request {
|
||||
page.navigation()
|
||||
.request()
|
||||
.widget()
|
||||
.gobject()
|
||||
.set_text(&text);
|
||||
page.navigation.request().widget().gobject().set_text(&text);
|
||||
}
|
||||
page.load(is_history);
|
||||
}
|
||||
@ -120,7 +112,7 @@ impl Item {
|
||||
self.page.update();
|
||||
|
||||
// Update tab loading indicator
|
||||
self.widget.gobject().set_loading(self.page().is_loading());
|
||||
self.widget.gobject().set_loading(self.page.is_loading());
|
||||
}
|
||||
|
||||
pub fn clean(
|
||||
@ -222,20 +214,6 @@ impl Item {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
pub fn id(&self) -> &GString {
|
||||
&self.id
|
||||
}
|
||||
|
||||
pub fn page(&self) -> &Rc<Page> {
|
||||
&self.page
|
||||
}
|
||||
|
||||
pub fn widget(&self) -> &Rc<Widget> {
|
||||
&self.widget
|
||||
}
|
||||
}
|
||||
|
||||
// Tools
|
||||
|
@ -21,18 +21,12 @@ use crate::Profile;
|
||||
use gtk::{
|
||||
gdk::Texture,
|
||||
gdk_pixbuf::Pixbuf,
|
||||
gio::{
|
||||
Cancellable, IOStream, NetworkAddress, SocketClient, SocketClientEvent, SocketConnectable,
|
||||
SocketProtocol, TlsCertificate, TlsClientConnection,
|
||||
},
|
||||
gio::{Cancellable, SocketClientEvent, TlsCertificate, TlsClientConnection},
|
||||
glib::{
|
||||
gformat, Bytes, GString, Priority, Regex, RegexCompileFlags, RegexMatchFlags, Uri,
|
||||
UriFlags, UriHideFlags,
|
||||
},
|
||||
prelude::{
|
||||
CancellableExt, Cast, EditableExt, IOStreamExt, IsA, OutputStreamExt, SocketClientExt,
|
||||
TlsConnectionExt,
|
||||
gformat, GString, Priority, Regex, RegexCompileFlags, RegexMatchFlags, Uri, UriFlags,
|
||||
UriHideFlags,
|
||||
},
|
||||
prelude::{CancellableExt, Cast, EditableExt, SocketClientExt, TlsConnectionExt},
|
||||
};
|
||||
use sqlite::Transaction;
|
||||
use std::{cell::RefCell, rc::Rc, time::Duration};
|
||||
@ -45,11 +39,11 @@ pub struct Page {
|
||||
browser_action: Rc<BrowserAction>,
|
||||
tab_action: Rc<TabAction>,
|
||||
// Components
|
||||
navigation: Rc<Navigation>,
|
||||
content: Rc<Content>,
|
||||
input: Rc<Input>,
|
||||
meta: Rc<Meta>,
|
||||
widget: Rc<Widget>,
|
||||
pub navigation: Rc<Navigation>,
|
||||
pub content: Rc<Content>,
|
||||
pub input: Rc<Input>,
|
||||
pub meta: Rc<Meta>,
|
||||
pub widget: Rc<Widget>,
|
||||
}
|
||||
|
||||
impl Page {
|
||||
@ -107,7 +101,7 @@ impl Page {
|
||||
.toggle(self.navigation.request().widget().gobject().text().as_str())
|
||||
{
|
||||
Ok(result) => Ok(result),
|
||||
Err(_) => Err(Error::Bookmark),
|
||||
Err(_) => Err(Error::Bookmark), // @TODO
|
||||
};
|
||||
self.update();
|
||||
result
|
||||
@ -405,53 +399,11 @@ impl Page {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn meta(&self) -> &Rc<Meta> {
|
||||
&self.meta
|
||||
}
|
||||
|
||||
pub fn navigation(&self) -> &Rc<Navigation> {
|
||||
&self.navigation
|
||||
}
|
||||
|
||||
pub fn widget(&self) -> &Rc<Widget> {
|
||||
&self.widget
|
||||
}
|
||||
|
||||
// Private helpers
|
||||
|
||||
// @TODO move outside
|
||||
fn load_gemini(&self, uri: Uri, is_history: bool) {
|
||||
// Stream wrapper for TLS connections
|
||||
fn auth(
|
||||
connection: impl IsA<IOStream>,
|
||||
connectable: impl IsA<SocketConnectable>,
|
||||
certificate: Option<TlsCertificate>,
|
||||
) -> impl IsA<IOStream> {
|
||||
if let Some(certificate) = certificate {
|
||||
// https://geminiprotocol.net/docs/protocol-specification.gmi#the-use-of-tls
|
||||
let tls_connection =
|
||||
TlsClientConnection::new(&connection, Some(&connectable)).unwrap(); // @TODO handle
|
||||
|
||||
// https://geminiprotocol.net/docs/protocol-specification.gmi#client-certificates
|
||||
tls_connection.set_certificate(&certificate);
|
||||
|
||||
// @TODO handle exceptions
|
||||
// https://geminiprotocol.net/docs/protocol-specification.gmi#closing-connections
|
||||
tls_connection.set_require_close_notify(true);
|
||||
|
||||
// @TODO host validation
|
||||
// https://geminiprotocol.net/docs/protocol-specification.gmi#tls-server-certificate-validation
|
||||
tls_connection.connect_accept_certificate(move |_, _, _| true);
|
||||
|
||||
// Take encrypted I/O stream
|
||||
tls_connection.upcast::<IOStream>()
|
||||
} else {
|
||||
// Take default I/O stream
|
||||
connection.upcast::<IOStream>()
|
||||
}
|
||||
}
|
||||
|
||||
// Init shared objects (async)
|
||||
// Init shared clones
|
||||
let cancellable = self.cancellable.borrow().clone();
|
||||
let update = self.browser_action.update().clone();
|
||||
let tab_action = self.tab_action.clone();
|
||||
@ -460,12 +412,9 @@ impl Page {
|
||||
let id = self.id.clone();
|
||||
let input = self.input.clone();
|
||||
let meta = self.meta.clone();
|
||||
let url = uri.clone().to_str();
|
||||
|
||||
// Init socket
|
||||
let client = SocketClient::new();
|
||||
client.set_protocol(SocketProtocol::Tcp);
|
||||
client.set_timeout(10); // @TODO
|
||||
let client = gemini::Client::new();
|
||||
|
||||
// Return PEM string match request
|
||||
let certificate = match self
|
||||
@ -479,16 +428,16 @@ impl Page {
|
||||
},
|
||||
None => {
|
||||
// Use unauthorized (random) TLS connection
|
||||
client.set_tls(true);
|
||||
client.socket.set_tls(true);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
// Listen for connection status updates
|
||||
client.connect_event({
|
||||
let update = update.clone();
|
||||
client.socket.connect_event({
|
||||
let id = id.clone();
|
||||
let meta = meta.clone();
|
||||
let update = update.clone();
|
||||
move |_, event, _, stream| {
|
||||
meta.set_status(match event {
|
||||
SocketClientEvent::Resolving => Status::Resolving,
|
||||
@ -497,8 +446,7 @@ impl Page {
|
||||
SocketClientEvent::Connected => Status::Connected,
|
||||
SocketClientEvent::ProxyNegotiating => Status::ProxyNegotiating,
|
||||
SocketClientEvent::ProxyNegotiated => Status::ProxyNegotiated,
|
||||
// This case have effect only for unauthorized (random) TLS connection
|
||||
// * see `fn auth` above to handle custom certificates
|
||||
// This match have effect only for unauthorized (random) TLS connection
|
||||
SocketClientEvent::TlsHandshaking => {
|
||||
// Handle certificate errors @TODO
|
||||
// https://geminiprotocol.net/docs/protocol-specification.gmi#tls-server-certificate-validation
|
||||
@ -517,75 +465,47 @@ impl Page {
|
||||
}
|
||||
});
|
||||
|
||||
// Implement shared [SocketConnectable](https://docs.gtk.org/gio/iface.SocketConnectable.html) interface
|
||||
// * required also on `auth` step ([SNI](https://geminiprotocol.net/docs/protocol-specification.gmi#server-name-indication))
|
||||
let connectable = NetworkAddress::new(
|
||||
&uri.host().unwrap(),
|
||||
if uri.port().is_positive() {
|
||||
uri.port() as u16
|
||||
} else {
|
||||
1965
|
||||
},
|
||||
);
|
||||
|
||||
// Create connection
|
||||
client.connect_async(
|
||||
&connectable.clone(),
|
||||
Some(&cancellable.clone()),
|
||||
move |connect| match connect {
|
||||
Ok(connection) => {
|
||||
|
||||
// Encrypt stream using authorization TLS
|
||||
let stream = auth(connection, connectable, certificate);
|
||||
|
||||
// Send request
|
||||
stream.output_stream().write_bytes_async(
|
||||
&Bytes::from(gformat!("{url}\r\n").as_bytes()),
|
||||
Priority::DEFAULT,
|
||||
Some(&cancellable.clone()),
|
||||
move |request| match request {
|
||||
Ok(_) => {
|
||||
// Read meta from input stream
|
||||
gemini::client::response::Meta::from_stream_async(
|
||||
stream.clone(),
|
||||
Some(Priority::DEFAULT),
|
||||
client.request_async(
|
||||
uri.clone(),
|
||||
None,
|
||||
Some(cancellable.clone()),
|
||||
move |result| match result
|
||||
{
|
||||
certificate,
|
||||
move |result| match result {
|
||||
Ok(response) => {
|
||||
// Route by status
|
||||
match response.status() {
|
||||
match response.meta.status {
|
||||
// https://geminiprotocol.net/docs/protocol-specification.gmi#input-expected
|
||||
gemini::client::response::meta::Status::Input |
|
||||
gemini::client::response::meta::Status::SensitiveInput => {
|
||||
// Format response
|
||||
let status = Status::Input;
|
||||
let title = match response.data() {
|
||||
Some(data) => data.value().as_str(),
|
||||
None => "Input expected",
|
||||
let title = match response.meta.data {
|
||||
Some(data) => data.value,
|
||||
None => gformat!("Input expected"),
|
||||
};
|
||||
|
||||
// Toggle input form variant
|
||||
match response.status() {
|
||||
match response.meta.status {
|
||||
gemini::client::response::meta::Status::SensitiveInput =>
|
||||
input.set_new_sensitive(
|
||||
tab_action,
|
||||
uri,
|
||||
Some(title),
|
||||
tab_action.clone(),
|
||||
uri.clone(),
|
||||
Some(&title),
|
||||
Some(1024),
|
||||
),
|
||||
_ =>
|
||||
input.set_new_response(
|
||||
tab_action,
|
||||
uri,
|
||||
Some(title),
|
||||
tab_action.clone(),
|
||||
uri.clone(),
|
||||
Some(&title),
|
||||
Some(1024),
|
||||
),
|
||||
}
|
||||
|
||||
// Update meta
|
||||
meta.set_status(status)
|
||||
.set_title(title);
|
||||
.set_title(&title);
|
||||
|
||||
// Update page
|
||||
update.activate(Some(&id));
|
||||
@ -594,24 +514,30 @@ impl Page {
|
||||
gemini::client::response::meta::Status::Success => {
|
||||
// Add history record
|
||||
if is_history {
|
||||
snap_history(navigation);
|
||||
snap_history(navigation.clone());
|
||||
}
|
||||
|
||||
// Route by MIME
|
||||
match response.mime() {
|
||||
match response.meta.mime {
|
||||
Some(gemini::client::response::meta::Mime::TextGemini) => {
|
||||
// Read entire input stream to buffer
|
||||
gemini::client::response::data::Text::from_stream_async(
|
||||
stream,
|
||||
response.connection.stream(),
|
||||
Some(Priority::DEFAULT),
|
||||
Some(cancellable.clone()),
|
||||
{
|
||||
let content = content.clone();
|
||||
let id = id.clone();
|
||||
let meta = meta.clone();
|
||||
let update = update.clone();
|
||||
let uri = uri.clone();
|
||||
move |result|{
|
||||
match result {
|
||||
Ok(buffer) => {
|
||||
// Set children component
|
||||
let text_gemini = content.to_text_gemini(
|
||||
&uri,
|
||||
buffer.data()
|
||||
&buffer.data
|
||||
);
|
||||
|
||||
let title = match text_gemini.meta_title() {
|
||||
@ -626,24 +552,17 @@ impl Page {
|
||||
// Update window components
|
||||
update.activate(Some(&id));
|
||||
}
|
||||
Err((reason, message)) => {
|
||||
Err(reason) => {
|
||||
// Define common data
|
||||
let status = Status::Failure;
|
||||
let title = "Oops";
|
||||
let description = match reason {
|
||||
gemini::client::response::data::text::Error::InputStream => match message {
|
||||
Some(error) => gformat!("{error}"),
|
||||
None => gformat!("Undefined connection error")
|
||||
} ,
|
||||
gemini::client::response::data::text::Error::BufferOverflow => gformat!("Buffer overflow"),
|
||||
gemini::client::response::data::text::Error::Decode => gformat!("Buffer decode error"),
|
||||
};
|
||||
let description = reason.to_string();
|
||||
|
||||
// Update widget
|
||||
content
|
||||
.to_status_failure()
|
||||
.set_title(title)
|
||||
.set_description(Some(description.as_str()));
|
||||
.set_description(Some(&description));
|
||||
|
||||
// Update meta
|
||||
meta.set_status(status)
|
||||
@ -654,6 +573,7 @@ impl Page {
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
Some(
|
||||
@ -670,7 +590,7 @@ impl Page {
|
||||
// Asynchronously move `InputStream` data from `SocketConnection` into the local `MemoryInputStream`
|
||||
// this action allows to count the bytes for loading widget and validate max size for incoming data
|
||||
gemini::gio::memory_input_stream::from_stream_async(
|
||||
stream,
|
||||
response.connection.stream(),
|
||||
Some(cancellable.clone()),
|
||||
Priority::DEFAULT,
|
||||
0x400, // 1024 bytes per chunk, optional step for images download tracking
|
||||
@ -681,6 +601,13 @@ impl Page {
|
||||
Some(&gformat!("Download: {total} bytes"))
|
||||
);
|
||||
},
|
||||
{
|
||||
let cancellable = cancellable.clone();
|
||||
let content = content.clone();
|
||||
let id = id.clone();
|
||||
let meta = meta.clone();
|
||||
let update = update.clone();
|
||||
let uri = uri.clone();
|
||||
move |result| match result {
|
||||
Ok(memory_input_stream) => {
|
||||
Pixbuf::from_stream_async(
|
||||
@ -734,29 +661,16 @@ impl Page {
|
||||
content
|
||||
.to_status_failure()
|
||||
.set_title(title)
|
||||
.set_description(Some(description.as_str()));
|
||||
.set_description(Some(&description));
|
||||
|
||||
// Update meta
|
||||
meta.set_status(status)
|
||||
.set_title(title);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
/* @TODO stream or download
|
||||
Some(
|
||||
ClientMime::AudioFlac | ClientMime::AudioMpeg | ClientMime::AudioOgg
|
||||
) => {
|
||||
// Update page meta
|
||||
meta.borrow_mut().status = Some(Status::Success);
|
||||
meta.borrow_mut().title = Some(gformat!("Stream"));
|
||||
|
||||
// Update page content
|
||||
// content.to_stream();
|
||||
|
||||
// Update window components
|
||||
update.activate(Some(&id));
|
||||
}, */
|
||||
_ => {
|
||||
// Define common data
|
||||
let status = Status::Failure;
|
||||
@ -767,7 +681,7 @@ impl Page {
|
||||
content
|
||||
.to_status_failure()
|
||||
.set_title(title)
|
||||
.set_description(Some(description.as_str()));
|
||||
.set_description(Some(&description));
|
||||
|
||||
// Update meta
|
||||
meta.set_status(status)
|
||||
@ -783,14 +697,14 @@ impl Page {
|
||||
// https://geminiprotocol.net/docs/protocol-specification.gmi#status-31-permanent-redirection
|
||||
gemini::client::response::meta::Status::PermanentRedirect => {
|
||||
// Extract redirection URL from response data
|
||||
match response.data() {
|
||||
match response.meta.data {
|
||||
Some(unresolved_url) => {
|
||||
// New URL from server MAY to be relative (according to the protocol specification),
|
||||
// resolve to absolute URI gobject using current request as the base for parser:
|
||||
// https://docs.gtk.org/glib/type_func.Uri.resolve_relative.html
|
||||
match Uri::resolve_relative(
|
||||
Some(&uri.to_string()),
|
||||
unresolved_url.value(),
|
||||
unresolved_url.value.as_str(),
|
||||
UriFlags::NONE,
|
||||
) {
|
||||
Ok(resolved_url) => {
|
||||
@ -836,7 +750,7 @@ impl Page {
|
||||
UriHideFlags::FRAGMENT | UriHideFlags::QUERY
|
||||
),
|
||||
// Set follow policy based on status code
|
||||
matches!(response.status(), gemini::client::response::meta::Status::PermanentRedirect),
|
||||
matches!(response.meta.status, gemini::client::response::meta::Status::PermanentRedirect),
|
||||
)
|
||||
.set_status(Status::Redirect) // @TODO is this status really wanted?
|
||||
.set_title("Redirect");
|
||||
@ -901,21 +815,21 @@ impl Page {
|
||||
|
||||
// Add history record
|
||||
if is_history {
|
||||
snap_history(navigation);
|
||||
snap_history(navigation.clone());
|
||||
}
|
||||
|
||||
// Update widget
|
||||
content
|
||||
.to_status_identity()
|
||||
.set_title(title)
|
||||
.set_description(match response.data() {
|
||||
Some(data) => Some(data.value().as_str()),
|
||||
None => match response.status() {
|
||||
gemini::client::response::meta::Status::CertificateUnauthorized => Some("Certificate not authorized"),
|
||||
gemini::client::response::meta::Status::CertificateInvalid => Some("Certificate not valid"),
|
||||
_ => Some("Client certificate required")
|
||||
.set_description(Some(&match response.meta.data {
|
||||
Some(data) => data.value,
|
||||
None => match response.meta.status {
|
||||
gemini::client::response::meta::Status::CertificateUnauthorized => gformat!("Certificate not authorized"),
|
||||
gemini::client::response::meta::Status::CertificateInvalid => gformat!("Certificate not valid"),
|
||||
_ => gformat!("Client certificate required")
|
||||
},
|
||||
});
|
||||
}));
|
||||
|
||||
// Update meta
|
||||
meta.set_status(status)
|
||||
@ -931,16 +845,16 @@ impl Page {
|
||||
|
||||
// Add history record
|
||||
if is_history {
|
||||
snap_history(navigation);
|
||||
snap_history(navigation.clone());
|
||||
}
|
||||
|
||||
// Update widget
|
||||
content
|
||||
.to_status_failure()
|
||||
.set_title(title)
|
||||
.set_description(Some(match response.data() {
|
||||
Some(data) => data.value().as_str(),
|
||||
None => "Status code yet not supported", // @TODO
|
||||
.set_description(Some(&match response.meta.data {
|
||||
Some(data) => data.value,
|
||||
None => gformat!("Status code yet not supported"),
|
||||
}));
|
||||
|
||||
// Update meta
|
||||
@ -952,67 +866,22 @@ impl Page {
|
||||
}
|
||||
}
|
||||
},
|
||||
Err((reason, message)) => {
|
||||
Err(reason) => {
|
||||
// Define common data
|
||||
let status = Status::Failure;
|
||||
let title = "Oops";
|
||||
let description = match reason {
|
||||
// Common
|
||||
gemini::client::response::meta::Error::InputStream => match message {
|
||||
Some(error) => gformat!("{error}"),
|
||||
None => gformat!("Input stream reading error")
|
||||
},
|
||||
gemini::client::response::meta::Error::Protocol => match message {
|
||||
Some(error) => gformat!("{error}"),
|
||||
None => gformat!("Incorrect protocol")
|
||||
},
|
||||
// Status
|
||||
gemini::client::response::meta::Error::StatusDecode => match message {
|
||||
Some(error) => gformat!("{error}"),
|
||||
None => gformat!("Could not detect status code")
|
||||
},
|
||||
gemini::client::response::meta::Error::StatusUndefined => match message {
|
||||
Some(error) => gformat!("{error}"),
|
||||
None => gformat!("Status code yet not supported")
|
||||
},
|
||||
gemini::client::response::meta::Error::StatusProtocol => match message {
|
||||
Some(error) => gformat!("{error}"),
|
||||
None => gformat!("Incorrect status code protocol")
|
||||
},
|
||||
// Data
|
||||
gemini::client::response::meta::Error::DataDecode => match message {
|
||||
Some(error) => gformat!("{error}"),
|
||||
None => gformat!("Incorrect data encoding")
|
||||
},
|
||||
gemini::client::response::meta::Error::DataProtocol => match message {
|
||||
Some(error) => gformat!("{error}"),
|
||||
None => gformat!("Incorrect data protocol")
|
||||
},
|
||||
// MIME
|
||||
gemini::client::response::meta::Error::MimeDecode => match message {
|
||||
Some(error) => gformat!("{error}"),
|
||||
None => gformat!("Incorrect MIME encoding")
|
||||
},
|
||||
gemini::client::response::meta::Error::MimeProtocol => match message {
|
||||
Some(error) => gformat!("{error}"),
|
||||
None => gformat!("Incorrect MIME protocol")
|
||||
},
|
||||
gemini::client::response::meta::Error::MimeUndefined => match message {
|
||||
Some(error) => gformat!("{error}"),
|
||||
None => gformat!("MIME type yet not supported (by library)")
|
||||
},
|
||||
};
|
||||
let description = reason.to_string();
|
||||
|
||||
// Add history record
|
||||
if is_history {
|
||||
snap_history(navigation);
|
||||
snap_history(navigation.clone());
|
||||
}
|
||||
|
||||
// Update widget
|
||||
content
|
||||
.to_status_failure()
|
||||
.set_title(title)
|
||||
.set_description(Some(description.as_str()));
|
||||
.set_description(Some(&description));
|
||||
|
||||
// Update meta
|
||||
meta.set_status(status)
|
||||
@ -1024,58 +893,6 @@ impl Page {
|
||||
}
|
||||
);
|
||||
}
|
||||
Err(reason) => {
|
||||
// Define common data
|
||||
let status = Status::Failure;
|
||||
let title = "Oops";
|
||||
|
||||
// Add history record
|
||||
if is_history {
|
||||
snap_history(navigation);
|
||||
}
|
||||
|
||||
// Update widget
|
||||
content
|
||||
.to_status_failure()
|
||||
.set_title(title)
|
||||
.set_description(Some(reason.message()));
|
||||
|
||||
// Update meta
|
||||
meta.set_status(status)
|
||||
.set_title(title);
|
||||
|
||||
// Update window
|
||||
update.activate(Some(&id));
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
Err(reason) => {
|
||||
// Define common data
|
||||
let status = Status::Failure;
|
||||
let title = "Oops";
|
||||
|
||||
// Add history record
|
||||
if is_history {
|
||||
snap_history(navigation);
|
||||
}
|
||||
|
||||
// Update widget
|
||||
content
|
||||
.to_status_failure()
|
||||
.set_title(title)
|
||||
.set_description(Some(reason.message()));
|
||||
|
||||
// Update meta
|
||||
meta.set_status(status)
|
||||
.set_title(title);
|
||||
|
||||
// Update window
|
||||
update.activate(Some(&id));
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Tools
|
||||
|
Loading…
x
Reference in New Issue
Block a user