Skip to content

Commit

Permalink
Merge pull request #257 from c410-f3r/misc
Browse files Browse the repository at this point in the history
Improve documentation
  • Loading branch information
c410-f3r authored Oct 30, 2024
2 parents cdf0afc + 96bbae8 commit ad8fbf9
Show file tree
Hide file tree
Showing 41 changed files with 277 additions and 213 deletions.
7 changes: 6 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,10 @@ Integration tests interact with external programs like `podman` or require an in

## Building

Taking aside common Rust tools that can be installed with `rustup` (https://rustup.rs/), at the current time it is only necessary to only have an C compiler to build the project. For example, you can use your favorite system package manager to install `gcc`.
Taking aside common Rust tools that can be installed with `rustup` (https://rustup.rs/), at the current time it is only necessary to have an C compiler to build the project. For example, you can use your favorite system package manager to install `gcc`.

## Submitting PRs

To accelerate and facilitate code review, PRs should contain a minimal description with a minimal amount of commits addressing one feature at the time. Code-related modifications should include corresponding unit, integration or property tests validating the intention.

The use of `unsafe` is discourage but when necessary, consider implementing MIRI tests to verify memory safety guarantees. If the introdution of `unsafe` enhances performance, also consider providing `#[bench]` benchmarks.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ Take a look at <https://bencher.dev/perf/wtx> to see all low-level benchmarks ov

When using a feature that requires network connection, it is often necessary to perform encrypted communication and since `wtx` is not hard-coded with a specific stream implementation, it is up to you to choose the best TLS provider.

Some utilities like `TokioRustlsConnector` or `TokioRustlsAcceptor` are provided to make things more convenient but keep in mind that it is still necessary to activate a crate that provides certificates for client usage.
Some utilities like `TokioRustlsConnector` or `TokioRustlsAcceptor` are available to make things more convenient but keep in mind that it is still necessary to activate a crate that provides certificates for client usage.

## Examples

Demonstrations of different use-cases can be found in the `wtx-instances` directory as well as in the documentation.

## Limitations

* Does not support systems with pointer length of 16 bits.
* Does not support systems with a pointer length of 16 bits.

* Expects the infallible sum of the lengths of an arbitrary number of slices, otherwise the program will likely trigger an overflow that can possibly result in unexpected operations. For example, in a 32bit system such a scenario should be viable without swap memory or through specific limiters like `ulimit`.
4 changes: 3 additions & 1 deletion wtx-docs/src/database-client/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@

# Client Connection

PostgreSQL is currently the only supported database. Implements <https://www.postgresql.org/docs/16/protocol.html>.
Provides a set of functions that establish connections, execute queries and manage data transactions with different databases.

At the current time PostgreSQL is the only supported database. Implements <https://www.postgresql.org/docs/16/protocol.html>.

More benchmarks are available at <https://github.com/diesel-rs/metrics>.

Expand Down
2 changes: 1 addition & 1 deletion wtx-docs/src/database-schema-manager/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Schema Management

Embedded and CLI workflows using raw SQL commands.
Embedded and CLI workflows using raw SQL commands. A schema manager is a tool thats allows developers to define, track and apply changes to database structures over time, ensuring consistency across different environments.

Activation feature is called `schema-manager`.

Expand Down
2 changes: 1 addition & 1 deletion wtx-docs/src/grpc/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

# gRPC

Basic implementation that currently supports only unary calls.
Basic implementation that currently only supports unary calls. gRPC is an high-performance remote procedure call framework developed by Google that enables efficient communication between distributed systems, particularly in microservices architectures.

`wtx` does not provide built-in deserialization or serialization utilities capable of manipulate protobuf files. Instead, users are free to choose any third-party that generates Rust bindings and implements the internal `Deserialize` and `Serialize` traits.

Expand Down
9 changes: 8 additions & 1 deletion wtx-docs/src/http-server-framework/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
# HTTP Server Framework

A small and fast to compile framework that can interact with many built-in features like PostgreSQL connections.
A small and fast to compile framework that can interact with many built-in features.

* Databases
* JSON
* Middlewares
* Streaming
* URI router
* WebSocket

If dynamic or nested routes are needed, then it is necessary to activate the `matchit` feature. Without it, only simple and flat routes will work.

Expand Down
6 changes: 3 additions & 3 deletions wtx-docs/src/http2/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# HTTP/2

Implementation of [RFC7541](https://datatracker.ietf.org/doc/html/rfc7541) and [RFC9113](https://datatracker.ietf.org/doc/html/rfc9113). In other words, a low-level HTTP.
Implementation of [RFC7541](https://datatracker.ietf.org/doc/html/rfc7541) and [RFC9113](https://datatracker.ietf.org/doc/html/rfc9113). HTTP/2 is the second major version of the Hypertext Transfer Protocol, introduced in 2015 to improve web performance, it addresses limitations of HTTP/1.1 while maintaining backwards compatibility.

Passes the `hpack-test-case` and the `h2spec` test suites. Due to official deprecation, server push and prioritization are not supported.
Passes the `hpack-test-case` and the `h2spec` test suites. Due to official deprecation, prioritization is not supported and due to the lack of third-party support, server-push is also not supported.

To use this functionality, it necessary to activate the `http2` feature.

Expand All @@ -16,4 +16,4 @@ To use this functionality, it necessary to activate the `http2` feature.

```rust,edition2021,no_run
{{#rustdoc_include ../../../wtx-instances/http2-examples/http2-server.rs}}
```
```
2 changes: 1 addition & 1 deletion wtx-docs/src/pool/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ An asynchronous pool of arbitrary objects where each element is dynamically crea

Can also be used for database connections, which is quite handy because it enhances the performance of executing commands and alleviates the use of hardware resources.

Activation feature is called `pool`.
To use this functionality, it necessary to activate the `pool` feature.

## Example

Expand Down
5 changes: 3 additions & 2 deletions wtx-docs/src/web-socket-over-http2/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
# WebSocket over HTTP/2


At the current time only servers support the handshake procedure defined in [RFC8441](https://https://datatracker.ietf.org/doc/html/rfc8441).
At the current time only servers support the handshake procedure defined in [RFC8441](https://datatracker.ietf.org/doc/html/rfc8441).

While HTTP/2 inherently supports full-duplex communication, web browsers typically don't expose this functionality directly to developers and that is why WebSocket tunneling over HTTP/2 is important.

1. Servers can efficiently handle multiple concurrent streams within a single TCP connection
2. Client applications can continue using existing WebSocket APIs without modification

For this particular scenario, the `no-masking` parameter defined in https://datatracker.ietf.org/doc/html/draft-damjanovic-websockets-nomasking-02 is also supported.

To use this functionality, it necessary to activate the `http2` and `web-socket` features.

## Example
Expand Down
6 changes: 4 additions & 2 deletions wtx-docs/src/web-socket/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# WebSocket

Implementation of [RFC6455](https://datatracker.ietf.org/doc/html/rfc6455) and [RFC7692](https://datatracker.ietf.org/doc/html/rfc7692).
Implementation of [RFC6455](https://datatracker.ietf.org/doc/html/rfc6455) and [RFC7692](https://datatracker.ietf.org/doc/html/rfc7692). WebSocket is a communication protocol that enables full-duplex communication between a client (typically a web browser) and a server over a single TCP connection. Unlike traditional HTTP, which is request-response based, WebSocket allows real-time data exchange without the need for polling.

To use this functionality, it necessary to activate the `web-socket` feature.

Expand All @@ -19,7 +19,9 @@ To get the most performance possible, try compiling your program with `RUSTFLAGS

## No masking

Although not officially endorsed, the `no-masking` parameter described at https://datatracker.ietf.org/doc/html/draft-damjanovic-websockets-nomasking-02 is supported to increase performance. If such a feature is not desirable, please make sure to check the handshake parameters to avoid accidental scenarios.
Although not officially endorsed, the `no-masking` parameter described at https://datatracker.ietf.org/doc/html/draft-damjanovic-websockets-nomasking-02 is supported to increase performance. If such a thing is not desirable, please make sure to check the handshake parameters to avoid accidental scenarios.

To make everything work as intended it is necessary that both parts, client and server, implement this feature. For example, web browser won't stop masking frames.

## Client Example

Expand Down
5 changes: 3 additions & 2 deletions wtx-instances/generic-examples/grpc-server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,10 @@ async fn main() -> wtx::Result<()> {
async fn wtx_generic_service_generic_method(
state: State<'_, (), GrpcManager<QuickProtobuf>, ReqResBuffer>,
) -> wtx::Result<StatusCode> {
let _generic_request: GenericRequest = state.ra.des_from_req_bytes(&state.req.rrd.body)?;
let _generic_request: GenericRequest =
state.stream_aux.des_from_req_bytes(&state.req.rrd.body)?;
state.req.rrd.clear();
state.ra.ser_to_res_bytes(
state.stream_aux.ser_to_res_bytes(
&mut state.req.rrd.body,
GenericResponse {
generic_response_field0: Cow::Borrowed(b"generic_response_value"),
Expand Down
2 changes: 1 addition & 1 deletion wtx-instances/generic-examples/web-socket-server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use wtx::{

#[tokio::main]
async fn main() -> wtx::Result<()> {
OptionedServer::tokio_web_socket(
OptionedServer::web_socket_tokio(
&wtx_instances::host_from_args(),
None,
|| {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ async fn main() -> wtx::Result<()> {

#[inline]
async fn login(state: State<'_, ConnAux, (), ReqResBuffer>) -> wtx::Result<StatusCode> {
let (session, rng) = state.ca;
let (session, rng) = state.conn_aux;
if session.content.lock().await.state().is_some() {
session.delete_session_cookie(&mut state.req.rrd).await?;
return Ok(StatusCode::Forbidden);
Expand All @@ -87,7 +87,7 @@ async fn login(state: State<'_, ConnAux, (), ReqResBuffer>) -> wtx::Result<Statu

#[inline]
async fn logout(state: StateClean<'_, ConnAux, (), ReqResBuffer>) -> wtx::Result<StatusCode> {
state.ca.0.delete_session_cookie(&mut state.req.rrd).await?;
state.conn_aux.0.delete_session_cookie(&mut state.req.rrd).await?;
Ok(StatusCode::Ok)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ async fn db(
state: StateClean<'_, (), Pool, ReqResBuffer>,
PathOwned(id): PathOwned<u32>,
) -> wtx::Result<StatusCode> {
let mut lock = state.ra.get().await?;
let mut lock = state.stream_aux.get().await?;
let record = lock.fetch_with_stmt("SELECT name FROM persons WHERE id = $1", (id,)).await?;
let name = record.decode::<_, &str>(0)?;
state.req.rrd.body.write_fmt(format_args!("Person of id `1` has name `{name}`"))?;
Expand Down
8 changes: 4 additions & 4 deletions wtx-instances/http2-examples/http2-server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use wtx::{

#[tokio::main]
async fn main() -> wtx::Result<()> {
OptionedServer::tokio_high_http2(
OptionedServer::http2_tokio(
&wtx_instances::host_from_args(),
auto,
|| {
Expand All @@ -36,7 +36,7 @@ async fn main() -> wtx::Result<()> {
|| Ok((Vector::new(), ReqResBuffer::empty())),
|headers, method, protocol| {
Ok(if is_web_socket_handshake(headers, method, protocol) {
StreamMode::Manual
StreamMode::Manual(())
} else {
StreamMode::Auto
})
Expand All @@ -60,13 +60,13 @@ async fn auto(mut ha: AutoStream<(), Vector<u8>>) -> Result<Response<ReqResBuffe
}

async fn manual(
mut hm: ManualServerStreamTokio<(), Vector<u8>, Http2Buffer, WriteHalf<TlsStream<TcpStream>>>,
mut hm: ManualServerStreamTokio<(), Http2Buffer, Vector<u8>, (), WriteHalf<TlsStream<TcpStream>>>,
) -> Result<(), wtx::Error> {
let rng = Xorshift64::from(simple_seed());
hm.headers.clear();
let mut wos = WebSocketOverStream::new(&hm.headers, false, rng, hm.stream).await?;
loop {
let mut frame = wos.read_frame(&mut hm.sa).await?;
let mut frame = wos.read_frame(&mut hm.stream_aux).await?;
match (frame.op_code(), frame.text_payload()) {
(_, Some(elem)) => println!("{elem}"),
(OpCode::Close, _) => break,
Expand Down
2 changes: 1 addition & 1 deletion wtx-instances/src/bin/autobahn-server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use wtx::{

#[tokio::main]
async fn main() -> wtx::Result<()> {
OptionedServer::tokio_web_socket(
OptionedServer::web_socket_tokio(
"127.0.0.1:9070",
None,
Flate2::default,
Expand Down
4 changes: 2 additions & 2 deletions wtx-instances/src/bin/h2load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use wtx::{

#[tokio::main]
async fn main() -> wtx::Result<()> {
OptionedServer::tokio_high_http2(
OptionedServer::http2_tokio(
"127.0.0.1:9000",
auto,
|| {
Expand All @@ -40,7 +40,7 @@ async fn auto(mut ha: AutoStream<(), ()>) -> Result<Response<ReqResBuffer>, wtx:
}

async fn manual(
_: ManualServerStreamTokio<(), (), Http2Buffer, OwnedWriteHalf>,
_: ManualServerStreamTokio<(), Http2Buffer, (), (), OwnedWriteHalf>,
) -> Result<(), wtx::Error> {
Ok(())
}
4 changes: 2 additions & 2 deletions wtx-instances/src/bin/h2spec-high-server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use wtx::{

#[tokio::main]
async fn main() -> wtx::Result<()> {
OptionedServer::tokio_high_http2(
OptionedServer::http2_tokio(
"127.0.0.1:9000",
auto,
|| Ok(((), Http2Buffer::new(Xorshift64::from(simple_seed())), Http2Params::default())),
Expand All @@ -34,7 +34,7 @@ async fn auto(mut ha: AutoStream<(), ()>) -> Result<Response<ReqResBuffer>, wtx:
}

async fn manual(
_: ManualServerStreamTokio<(), (), Http2Buffer, OwnedWriteHalf>,
_: ManualServerStreamTokio<(), Http2Buffer, (), (), OwnedWriteHalf>,
) -> Result<(), wtx::Error> {
Ok(())
}
4 changes: 2 additions & 2 deletions wtx/src/grpc/grpc_res_middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ where
async fn apply_res_middleware(
&self,
_: &mut CA,
ra: &mut GrpcManager<DRSR>,
res: Response<&mut ReqResBuffer>,
sa: &mut GrpcManager<DRSR>,
) -> Result<(), E> {
res.rrd.headers_mut().push_from_iter_many([
Header::from_name_and_value(
Expand All @@ -30,7 +30,7 @@ where
is_sensitive: false,
is_trailer: true,
name: b"grpc-status",
value: [ra.status_code_mut().number_as_str().as_bytes()].into_iter(),
value: [sa.status_code_mut().number_as_str().as_bytes()].into_iter(),
},
])?;
Ok(())
Expand Down
8 changes: 4 additions & 4 deletions wtx/src/http/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use crate::{

/// Used as an auxiliary tool for tests.
#[inline]
pub fn state_tuple_wo_uri<CA, RA>(
(ca, ra, req): &mut (CA, RA, Request<ReqResBuffer>),
) -> (&mut CA, &mut RA, Request<(&mut Vector<u8>, &mut Headers)>) {
pub fn state_tuple_wo_uri<CA, SA>(
(conn_aux, stream_aux, req): &mut (CA, SA, Request<ReqResBuffer>),
) -> (&mut CA, &mut SA, Request<(&mut Vector<u8>, &mut Headers)>) {
let (body, headers, _) = req.rrd.parts_mut();
(ca, ra, Request { method: req.method, rrd: (body, headers), version: req.version })
(conn_aux, stream_aux, Request { method: req.method, rrd: (body, headers), version: req.version })
}
4 changes: 2 additions & 2 deletions wtx/src/http/optioned_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
// FIXME(STABLE): Return type notation

#[cfg(all(feature = "http2", feature = "tokio"))]
mod tokio_http2;
mod http2_tokio;
#[cfg(all(feature = "pool", feature = "tokio", feature = "web-socket-handshake"))]
mod tokio_web_socket;
mod web_socket_tokio;

/// Optioned abstractions of low-level servers.
#[derive(Debug)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
http::{
optioned_server::OptionedServer, AutoStream, Headers, ManualServerStreamTokio, ManualStream,
Method, Protocol, ReqResBuffer, Response, StreamMode,
optioned_server::OptionedServer, AutoStream, Headers, ManualServerStreamTokio, Method,
Protocol, ReqResBuffer, Response, StreamMode,
},
http2::{Http2Buffer, Http2ErrorCode, Http2Params, Http2Tokio},
misc::{Either, FnFut, StreamReader, StreamWriter},
Expand All @@ -12,15 +12,15 @@ use tokio::net::{TcpListener, TcpStream};
impl OptionedServer {
/// Optioned HTTP/2 server using tokio.
#[inline]
pub async fn tokio_high_http2<A, ACPT, CA, E, M, N, SA, SR, SW>(
pub async fn http2_tokio<A, ACPT, CA, E, M, N, SA, SMA, SR, SW>(
addr: &str,
auto_cb: A,
conn_cb: impl Clone + Fn() -> crate::Result<(CA, Http2Buffer, Http2Params)> + Send + 'static,
err_cb: impl Clone + Fn(E) + Send + 'static,
manual_cb: M,
stream_cb: impl Clone + Fn() -> crate::Result<(SA, ReqResBuffer)> + Send + 'static,
stream_mode_cb: impl Clone
+ Fn(&mut Headers, Method, Option<Protocol>) -> Result<StreamMode, E>
+ Fn(&mut Headers, Method, Option<Protocol>) -> Result<StreamMode<SMA>, E>
+ Send
+ Sync
+ 'static,
Expand All @@ -40,12 +40,13 @@ impl OptionedServer {
ACPT: Send + 'static,
E: From<crate::Error> + Send + 'static,
M: Clone
+ FnFut<(ManualServerStreamTokio<CA, SA, Http2Buffer, SW>,), Result = Result<(), E>>
+ FnFut<(ManualServerStreamTokio<CA, Http2Buffer, SA, SMA, SW>,), Result = Result<(), E>>
+ Send
+ 'static,
M::Future: Send,
N: Future<Output = crate::Result<(SR, SW)>> + Send,
SA: Send + 'static,
SMA: Send + 'static,
SR: Send + StreamReader<read(..): Send, read_skip(..): Send> + Unpin + 'static,
SW: Send + StreamWriter<write_all(..): Send, write_all_vectored(..): Send> + Unpin + 'static,
for<'handle> &'handle A: Send,
Expand Down Expand Up @@ -76,12 +77,12 @@ impl OptionedServer {
.await?;
let _frame_reader_jh = tokio::spawn(frame_reader);
loop {
let (sa, rrb) = conn_stream_cb()?;
let (stream_aux, rrb) = conn_stream_cb()?;
let (mut stream, headers_opt) = match http2
.stream(rrb, |headers, method, protocol| {
Ok::<_, E>(match conn_stream_mode_cb(headers, method, protocol)? {
StreamMode::Auto => None,
StreamMode::Manual => Some(mem::take(headers)),
StreamMode::Manual(ma) => Some((mem::take(headers), ma)),
})
})
.await?
Expand All @@ -95,14 +96,15 @@ impl OptionedServer {
let stream_manual_cb = conn_manual_cb.clone();
let _stream_jh = tokio::spawn(async move {
let stream_fun = async {
if let Some(headers) = headers_opt? {
if let Some((headers, stream_mode_aux)) = headers_opt? {
stream_manual_cb
.call((ManualStream {
ca: stream_ca,
.call((ManualServerStreamTokio {
conn_aux: stream_ca,
headers,
peer,
sa,
stream: stream.clone(),
stream_aux,
stream_mode_aux,
},))
.await?;
return Ok(());
Expand All @@ -112,7 +114,7 @@ impl OptionedServer {
return Ok(());
}
let req = local_rrb.into_http2_request(stream.method());
let _as = AutoStream { ca: stream_ca, peer, req, sa };
let _as = AutoStream { conn_aux: stream_ca, peer, req, stream_aux };
let res = stream_auto_cb.call((_as,)).await?;
if stream.send_res(res).await?.is_closed() {
return Ok(());
Expand Down
Loading

0 comments on commit ad8fbf9

Please sign in to comment.