Skip to content

Commit

Permalink
move body component to data::text namespace
Browse files Browse the repository at this point in the history
  • Loading branch information
yggverse committed Oct 31, 2024
1 parent d5cea24 commit 20270d6
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 210 deletions.
4 changes: 1 addition & 3 deletions src/client/response.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
//! Read and parse Gemini response as GObject
//! Read and parse Gemini response as Object

pub mod body;
pub mod data;
pub mod meta;

pub use body::Body;
pub use meta::Meta;
200 changes: 0 additions & 200 deletions src/client/response/body.rs

This file was deleted.

5 changes: 0 additions & 5 deletions src/client/response/body/error.rs

This file was deleted.

3 changes: 2 additions & 1 deletion src/client/response/data.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Gemini response could have different MIME type for data.
//! Use one of these components to parse response according to content type expected.
//! Use one of components below to parse response according to content type expected.
//!
//! * MIME type could be detected using `client::response::Meta` parser

pub mod text;
pub use text::Text;
121 changes: 121 additions & 0 deletions src/client/response/data/text.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//! Tools for Text-based response

pub mod error;
pub use error::Error;

// Local dependencies
use gio::{
prelude::{IOStreamExt, InputStreamExt},
Cancellable, SocketConnection,
};
use glib::{GString, Priority};

// Default limits
pub const BUFFER_CAPACITY: usize = 0x400; // 1024
pub const BUFFER_MAX_SIZE: usize = 0xfffff; // 1M

/// Container for text-based response data
pub struct Text {
data: GString,
}

impl Text {
// Constructors

/// Create new `Self` with options
pub fn new(data: GString) -> Self {
Self { data }
}

/// Create new `Self` from UTF-8 buffer
pub fn from_utf8(buffer: &[u8]) -> Result<Self, (Error, Option<&str>)> {
match GString::from_utf8(buffer.into()) {
Ok(data) => Ok(Self::new(data)),
Err(_) => Err((Error::Decode, None)),
}
}

/// Asynchronously create new `Self` from [InputStream](https://docs.gtk.org/gio/class.InputStream.html)
/// for given [SocketConnection](https://docs.gtk.org/gio/class.SocketConnection.html)
pub fn from_socket_connection_async(
socket_connection: SocketConnection,
priority: Option<Priority>,
cancellable: Option<Cancellable>,
on_complete: impl FnOnce(Result<Self, (Error, Option<&str>)>) + 'static,
) {
read_all_from_socket_connection_async(
Vec::with_capacity(BUFFER_CAPACITY),
socket_connection,
match cancellable {
Some(value) => Some(value),
None => None::<Cancellable>,
},
match priority {
Some(value) => value,
None => Priority::DEFAULT,
},
|result| match result {
Ok(buffer) => on_complete(Self::from_utf8(&buffer)),
Err(reason) => on_complete(Err(reason)),
},
);
}

// Getters

/// Get reference to `Self` data
pub fn data(&self) -> &GString {
&self.data
}
}

// Tools

/// Asynchronously read all bytes from [InputStream](https://docs.gtk.org/gio/class.InputStream.html)
/// for given [SocketConnection](https://docs.gtk.org/gio/class.SocketConnection.html)
///
/// Return UTF-8 buffer collected.
///
/// * this function implements low-level helper for `Text::from_socket_connection_async`, also provides public API for external integrations
/// * requires `SocketConnection` instead of `InputStream` to keep connection alive (by increasing reference count in async context) @TODO
pub fn read_all_from_socket_connection_async(
mut buffer: Vec<u8>,
socket_connection: SocketConnection,
cancelable: Option<Cancellable>,
priority: Priority,
callback: impl FnOnce(Result<Vec<u8>, (Error, Option<&str>)>) + 'static,
) {
socket_connection.input_stream().read_bytes_async(
BUFFER_CAPACITY,
priority,
cancelable.clone().as_ref(),
move |result| match result {
Ok(bytes) => {
// No bytes were read, end of stream
if bytes.len() == 0 {
return callback(Ok(buffer));
}

// Validate overflow
if buffer.len() + bytes.len() > BUFFER_MAX_SIZE {
return callback(Err((Error::BufferOverflow, None)));
}

// Save chunks to buffer
for &byte in bytes.iter() {
buffer.push(byte);
}

// Continue bytes reading
read_all_from_socket_connection_async(
buffer,
socket_connection,
cancelable,
priority,
callback,
);
}
Err(reason) => callback(Err((Error::InputStream, Some(reason.message())))),
},
);
}
4 changes: 3 additions & 1 deletion src/client/response/data/text/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#[derive(Debug)]
pub enum Error {
// nothing yet..
BufferOverflow,
Decode,
InputStream,
}

0 comments on commit 20270d6

Please sign in to comment.