mirror of
https://github.com/YGGverse/ggemini.git
synced 2026-03-31 17:15:31 +00:00
implement titan and gemini requests in single file
This commit is contained in:
parent
0cb5ff9cbc
commit
6da4c2ed52
5 changed files with 87 additions and 112 deletions
|
|
@ -53,9 +53,9 @@ use ggemini::client::{
|
||||||
|
|
||||||
fn main() -> ExitCode {
|
fn main() -> ExitCode {
|
||||||
Client::new().request_async(
|
Client::new().request_async(
|
||||||
Request::gemini( // or `Request::titan`
|
Request::Gemini { // or `Request::Titan`
|
||||||
Uri::parse("gemini://geminiprotocol.net/", UriFlags::NONE).unwrap(),
|
uri: Uri::parse("gemini://geminiprotocol.net/", UriFlags::NONE).unwrap(),
|
||||||
),
|
},
|
||||||
Priority::DEFAULT,
|
Priority::DEFAULT,
|
||||||
Cancellable::new(),
|
Cancellable::new(),
|
||||||
None, // optional `GTlsCertificate`
|
None, // optional `GTlsCertificate`
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ pub mod request;
|
||||||
pub mod response;
|
pub mod response;
|
||||||
|
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
pub use request::{Gemini, Request, Titan};
|
pub use request::Request;
|
||||||
pub use response::Response;
|
pub use response::Response;
|
||||||
|
|
||||||
// Local dependencies
|
// Local dependencies
|
||||||
|
|
@ -67,7 +67,7 @@ impl Connection {
|
||||||
Some(&cancellable.clone()),
|
Some(&cancellable.clone()),
|
||||||
move |result| match result {
|
move |result| match result {
|
||||||
Ok(_) => match request {
|
Ok(_) => match request {
|
||||||
Request::Gemini(..) => {
|
Request::Gemini { .. } => {
|
||||||
Response::from_connection_async(self, priority, cancellable, |result| {
|
Response::from_connection_async(self, priority, cancellable, |result| {
|
||||||
callback(match result {
|
callback(match result {
|
||||||
Ok(response) => Ok(response),
|
Ok(response) => Ok(response),
|
||||||
|
|
@ -75,8 +75,8 @@ impl Connection {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Request::Titan(this) => output_stream.write_bytes_async(
|
Request::Titan { data, .. } => output_stream.write_bytes_async(
|
||||||
&this.data,
|
&data,
|
||||||
priority,
|
priority,
|
||||||
Some(&cancellable.clone()),
|
Some(&cancellable.clone()),
|
||||||
move |result| match result {
|
move |result| match result {
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,24 @@
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod gemini;
|
|
||||||
pub mod titan;
|
|
||||||
|
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
pub use gemini::Gemini;
|
|
||||||
pub use titan::Titan;
|
|
||||||
|
|
||||||
// Local dependencies
|
// Local dependencies
|
||||||
|
|
||||||
use gio::NetworkAddress;
|
use gio::NetworkAddress;
|
||||||
use glib::Uri;
|
use glib::{Bytes, Uri, UriHideFlags};
|
||||||
|
|
||||||
/// Single `Request` implementation for different protocols
|
/// Single `Request` implementation for different protocols
|
||||||
pub enum Request {
|
pub enum Request {
|
||||||
Gemini(Gemini),
|
Gemini {
|
||||||
Titan(Titan),
|
uri: Uri,
|
||||||
|
},
|
||||||
|
Titan {
|
||||||
|
uri: Uri,
|
||||||
|
data: Bytes,
|
||||||
|
/// MIME type is optional attribute by Titan protocol specification,
|
||||||
|
/// but server MAY reject the request without `mime` value provided.
|
||||||
|
mime: Option<String>,
|
||||||
|
token: Option<String>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Request {
|
impl Request {
|
||||||
|
|
@ -23,16 +27,38 @@ impl Request {
|
||||||
/// Generate header string for `Self`
|
/// Generate header string for `Self`
|
||||||
pub fn header(&self) -> String {
|
pub fn header(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Self::Gemini(ref this) => this.header(),
|
Self::Gemini { uri } => format!("{uri}\r\n"),
|
||||||
Self::Titan(ref this) => this.header(),
|
Self::Titan {
|
||||||
|
uri,
|
||||||
|
data,
|
||||||
|
mime,
|
||||||
|
token,
|
||||||
|
} => {
|
||||||
|
let mut header = format!(
|
||||||
|
"{};size={}",
|
||||||
|
uri.to_string_partial(UriHideFlags::QUERY),
|
||||||
|
data.len()
|
||||||
|
);
|
||||||
|
if let Some(ref mime) = mime {
|
||||||
|
header.push_str(&format!(";mime={mime}"));
|
||||||
|
}
|
||||||
|
if let Some(ref token) = token {
|
||||||
|
header.push_str(&format!(";token={token}"));
|
||||||
|
}
|
||||||
|
if let Some(query) = uri.query() {
|
||||||
|
header.push_str(&format!("?{query}"));
|
||||||
|
}
|
||||||
|
header.push_str("\r\n");
|
||||||
|
header
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get reference to `Self` [Uri](https://docs.gtk.org/glib/struct.Uri.html)
|
/// Get reference to `Self` [Uri](https://docs.gtk.org/glib/struct.Uri.html)
|
||||||
pub fn uri(&self) -> &Uri {
|
pub fn uri(&self) -> &Uri {
|
||||||
match self {
|
match self {
|
||||||
Self::Gemini(ref this) => &this.uri,
|
Self::Gemini { uri } => uri,
|
||||||
Self::Titan(ref this) => &this.uri,
|
Self::Titan { uri, .. } => uri,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -44,3 +70,45 @@ impl Request {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_gemini_header() {
|
||||||
|
use glib::UriFlags;
|
||||||
|
|
||||||
|
const REQUEST: &str = "gemini://geminiprotocol.net/";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Request::Gemini {
|
||||||
|
uri: Uri::parse(REQUEST, UriFlags::NONE).unwrap()
|
||||||
|
}
|
||||||
|
.header(),
|
||||||
|
format!("{REQUEST}\r\n")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_titan_header() {
|
||||||
|
use glib::UriFlags;
|
||||||
|
|
||||||
|
const DATA: &[u8] = &[1, 2, 3];
|
||||||
|
const MIME: &str = "plain/text";
|
||||||
|
const TOKEN: &str = "token";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Request::Titan {
|
||||||
|
uri: Uri::parse(
|
||||||
|
"titan://geminiprotocol.net/raw/path?key=value",
|
||||||
|
UriFlags::NONE
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
data: Bytes::from(DATA),
|
||||||
|
mime: Some(MIME.to_string()),
|
||||||
|
token: Some(TOKEN.to_string())
|
||||||
|
}
|
||||||
|
.header(),
|
||||||
|
format!(
|
||||||
|
"titan://geminiprotocol.net/raw/path;size={};mime={MIME};token={TOKEN}?key=value\r\n",
|
||||||
|
DATA.len(),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
use glib::Uri;
|
|
||||||
|
|
||||||
/// [Gemini](https://geminiprotocol.net/docs/protocol-specification.gmi) protocol enum object for `Request`
|
|
||||||
pub struct Gemini {
|
|
||||||
pub uri: Uri,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Gemini {
|
|
||||||
// Getters
|
|
||||||
|
|
||||||
/// Get header string for `Self`
|
|
||||||
pub fn header(&self) -> String {
|
|
||||||
format!("{}\r\n", self.uri)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn header() {
|
|
||||||
use super::{super::Request, Gemini};
|
|
||||||
use glib::UriFlags;
|
|
||||||
|
|
||||||
const REQUEST: &str = "gemini://geminiprotocol.net/";
|
|
||||||
assert_eq!(
|
|
||||||
Request::Gemini(Gemini {
|
|
||||||
uri: Uri::parse(REQUEST, UriFlags::NONE).unwrap()
|
|
||||||
})
|
|
||||||
.header(),
|
|
||||||
format!("{REQUEST}\r\n")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
use glib::{Bytes, Uri, UriHideFlags};
|
|
||||||
|
|
||||||
/// Formatted [Titan](gemini://transjovian.org/titan/page/The%20Titan%20Specification) `Request`
|
|
||||||
pub struct Titan {
|
|
||||||
pub uri: Uri,
|
|
||||||
pub data: Bytes,
|
|
||||||
/// MIME type is optional attribute by Titan protocol specification,
|
|
||||||
/// but server MAY reject the request without `mime` value provided.
|
|
||||||
pub mime: Option<String>,
|
|
||||||
pub token: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Titan {
|
|
||||||
// Getters
|
|
||||||
|
|
||||||
/// Get header string for `Self`
|
|
||||||
pub fn header(&self) -> String {
|
|
||||||
let mut header = format!(
|
|
||||||
"{};size={}",
|
|
||||||
self.uri.to_string_partial(UriHideFlags::QUERY),
|
|
||||||
self.data.len()
|
|
||||||
);
|
|
||||||
if let Some(ref mime) = self.mime {
|
|
||||||
header.push_str(&format!(";mime={mime}"));
|
|
||||||
}
|
|
||||||
if let Some(ref token) = self.token {
|
|
||||||
header.push_str(&format!(";token={token}"));
|
|
||||||
}
|
|
||||||
if let Some(query) = self.uri.query() {
|
|
||||||
header.push_str(&format!("?{query}"));
|
|
||||||
}
|
|
||||||
header.push_str("\r\n");
|
|
||||||
header
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn header() {
|
|
||||||
use super::{super::Request, Titan};
|
|
||||||
use glib::UriFlags;
|
|
||||||
|
|
||||||
const DATA: &[u8] = &[1, 2, 3];
|
|
||||||
const MIME: &str = "plain/text";
|
|
||||||
const TOKEN: &str = "token";
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
Request::Titan(Titan {
|
|
||||||
uri: Uri::parse(
|
|
||||||
"titan://geminiprotocol.net/raw/path?key=value",
|
|
||||||
UriFlags::NONE
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
data: Bytes::from(DATA),
|
|
||||||
mime: Some(MIME.to_string()),
|
|
||||||
token: Some(TOKEN.to_string())
|
|
||||||
})
|
|
||||||
.header(),
|
|
||||||
format!(
|
|
||||||
"titan://geminiprotocol.net/raw/path;size={};mime={MIME};token={TOKEN}?key=value\r\n",
|
|
||||||
DATA.len(),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue