Skip to content

Commit b94ec3d

Browse files
committed
Merge branch 'develop' into hyperwallet-client_lib
Conflicts: Cargo.lock
2 parents 9d66f39 + 6597ae1 commit b94ec3d

File tree

8 files changed

+474
-175
lines changed

8 files changed

+474
-175
lines changed

Cargo.lock

Lines changed: 66 additions & 91 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "hyperware_process_lib"
33
authors = ["Sybil Technologies AG"]
4-
version = "1.2.0"
4+
version = "2.0.1"
55
edition = "2021"
66
description = "A library for writing Hyperware processes in Rust."
77
homepage = "https://hyperware.ai"
@@ -44,4 +44,4 @@ tracing = { version = "0.1", optional = true }
4444
tracing-error = { version = "0.2", optional = true }
4545
tracing-subscriber = { version = "0.3", features = ["env-filter", "json", "std"], optional = true }
4646
url = "2.4.1"
47-
wit-bindgen = "0.36.0"
47+
wit-bindgen = "0.42.1"

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,13 @@ Library of functions for more ergonomic Hyperware Rust process development.
77
[Crate can be found here](https://crates.io/crates/hyperware_process_lib).
88

99
See the [Hyperware Book](https://book.hyperware.ai) for a guide on how to use this library to write Hyperware apps in Rust.
10+
11+
## Dependencies
12+
13+
`process_lib` v`2.x.y` uses [`wit-bindgen`](https://github.com/bytecodealliance/wit-bindgen) v`0.42.1`.
14+
Processes depending on `process_lib` must also use that version.
15+
16+
`process_lib` version | `wit-bindgen` version
17+
--------------------- | ---------------------
18+
`2.x.y` | `0.42.1`
19+
`1.x.y` | `0.36.0`

src/http/server.rs

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -878,19 +878,17 @@ impl HttpServer {
878878
Ok(())
879879
}
880880

881-
/// Serve static files from a given directory by binding all of them
882-
/// in http-server to their filesystem path.
883-
///
884-
/// The directory is relative to the `pkg` folder within this package's drive.
885-
///
886-
/// The config `static_content` field will be ignored in favor of the files' contents.
887-
/// An error will be returned if the file does not exist.
888-
pub fn serve_ui(
881+
/// Helper function to traverse a UI directory and apply an operation to each file.
882+
/// This is used by both serve_ui and unserve_ui to avoid code duplication.
883+
fn traverse_ui_directory<F>(
889884
&mut self,
890885
directory: &str,
891-
roots: Vec<&str>,
892-
config: HttpBindingConfig,
893-
) -> Result<(), HttpServerError> {
886+
roots: &[&str],
887+
mut file_handler: F,
888+
) -> Result<(), HttpServerError>
889+
where
890+
F: FnMut(&mut Self, &str, &[&str], bool) -> Result<(), HttpServerError>,
891+
{
894892
let our = crate::our();
895893
let initial_path = format!("{}/pkg/{}", our.package_id(), directory);
896894

@@ -927,22 +925,17 @@ impl HttpServer {
927925
queue.push_back(entry.path);
928926
}
929927
FileType::File => {
930-
// if it's a file, serve it statically at its path
931-
// if it's `index.html`, serve additionally as the root
932-
if entry.path.ends_with("index.html") {
933-
for root in &roots {
934-
self.serve_file_raw_path(
935-
&entry.path,
936-
vec![root, &entry.path.replace(&initial_path, "")],
937-
config.clone(),
938-
)?;
928+
let relative_path = entry.path.replace(&initial_path, "");
929+
let is_index = entry.path.ends_with("index.html");
930+
931+
// Call the handler with the file path and whether it's an index file
932+
file_handler(self, &entry.path, &[relative_path.as_str()], is_index)?;
933+
934+
// If it's an index file, also handle the root paths
935+
if is_index {
936+
for root in roots {
937+
file_handler(self, &entry.path, &[root], true)?;
939938
}
940-
} else {
941-
self.serve_file_raw_path(
942-
&entry.path,
943-
vec![&entry.path.replace(&initial_path, "")],
944-
config.clone(),
945-
)?;
946939
}
947940
}
948941
_ => {
@@ -955,6 +948,40 @@ impl HttpServer {
955948
Ok(())
956949
}
957950

951+
/// Serve static files from a given directory by binding all of them
952+
/// in http-server to their filesystem path.
953+
///
954+
/// The directory is relative to the `pkg` folder within this package's drive.
955+
///
956+
/// The config `static_content` field will be ignored in favor of the files' contents.
957+
/// An error will be returned if the file does not exist.
958+
pub fn serve_ui(
959+
&mut self,
960+
directory: &str,
961+
roots: Vec<&str>,
962+
config: HttpBindingConfig,
963+
) -> Result<(), HttpServerError> {
964+
self.traverse_ui_directory(directory, &roots, |server, file_path, paths, _is_index| {
965+
server.serve_file_raw_path(file_path, paths.to_vec(), config.clone())
966+
})
967+
}
968+
969+
/// Unserve static files from a given directory by unbinding all of them
970+
/// from http-server that were previously bound by serve_ui.
971+
///
972+
/// The directory is relative to the `pkg` folder within this package's drive.
973+
///
974+
/// This mirrors the logic of serve_ui but calls unbind_http_path instead.
975+
pub fn unserve_ui(&mut self, directory: &str, roots: Vec<&str>) -> Result<(), HttpServerError> {
976+
self.traverse_ui_directory(directory, &roots, |server, _file_path, paths, _is_index| {
977+
// Unbind each path that was bound
978+
for path in paths {
979+
server.unbind_http_path(*path)?;
980+
}
981+
Ok(())
982+
})
983+
}
984+
958985
/// Handle a WebSocket open event from the HTTP server.
959986
pub fn handle_websocket_open(&mut self, path: &str, channel_id: u32) {
960987
self.ws_channels

src/hypermap.rs

Lines changed: 70 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1536,36 +1536,20 @@ impl Serialize for CacherRequest {
15361536
S: Serializer,
15371537
{
15381538
match self {
1539-
CacherRequest::GetManifest => {
1540-
let mut map = serializer.serialize_map(Some(1))?;
1541-
map.serialize_entry("GetManifest", &())?;
1542-
map.end()
1543-
}
1539+
CacherRequest::GetManifest => serializer.serialize_str("GetManifest"),
15441540
CacherRequest::GetLogCacheContent(path) => {
15451541
let mut map = serializer.serialize_map(Some(1))?;
15461542
map.serialize_entry("GetLogCacheContent", path)?;
15471543
map.end()
15481544
}
1549-
CacherRequest::GetStatus => {
1550-
let mut map = serializer.serialize_map(Some(1))?;
1551-
map.serialize_entry("GetStatus", &())?;
1552-
map.end()
1553-
}
1545+
CacherRequest::GetStatus => serializer.serialize_str("GetStatus"),
15541546
CacherRequest::GetLogsByRange(request) => {
15551547
let mut map = serializer.serialize_map(Some(1))?;
15561548
map.serialize_entry("GetLogsByRange", request)?;
15571549
map.end()
15581550
}
1559-
CacherRequest::StartProviding => {
1560-
let mut map = serializer.serialize_map(Some(1))?;
1561-
map.serialize_entry("StartProviding", &())?;
1562-
map.end()
1563-
}
1564-
CacherRequest::StopProviding => {
1565-
let mut map = serializer.serialize_map(Some(1))?;
1566-
map.serialize_entry("StopProviding", &())?;
1567-
map.end()
1568-
}
1551+
CacherRequest::StartProviding => serializer.serialize_str("StartProviding"),
1552+
CacherRequest::StopProviding => serializer.serialize_str("StopProviding"),
15691553
CacherRequest::SetNodes(nodes) => {
15701554
let mut map = serializer.serialize_map(Some(1))?;
15711555
map.serialize_entry("SetNodes", nodes)?;
@@ -1591,8 +1575,32 @@ impl<'de> Deserialize<'de> for CacherRequest {
15911575
type Value = CacherRequest;
15921576

15931577
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1594-
formatter
1595-
.write_str("a map with a single key representing the CacherRequest variant")
1578+
formatter.write_str("a string for unit variants or a map for other variants")
1579+
}
1580+
1581+
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
1582+
where
1583+
E: de::Error,
1584+
{
1585+
match value {
1586+
"GetManifest" => Ok(CacherRequest::GetManifest),
1587+
"GetStatus" => Ok(CacherRequest::GetStatus),
1588+
"StartProviding" => Ok(CacherRequest::StartProviding),
1589+
"StopProviding" => Ok(CacherRequest::StopProviding),
1590+
_ => Err(de::Error::unknown_variant(
1591+
value,
1592+
&[
1593+
"GetManifest",
1594+
"GetLogCacheContent",
1595+
"GetStatus",
1596+
"GetLogsByRange",
1597+
"StartProviding",
1598+
"StopProviding",
1599+
"SetNodes",
1600+
"Reset",
1601+
],
1602+
)),
1603+
}
15961604
}
15971605

15981606
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
@@ -1603,19 +1611,20 @@ impl<'de> Deserialize<'de> for CacherRequest {
16031611
.next_entry::<String, serde_json::Value>()?
16041612
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
16051613

1614+
// Ensure there are no extra entries
1615+
if map.next_entry::<String, serde_json::Value>()?.is_some() {
1616+
return Err(de::Error::custom("unexpected extra entries in map"));
1617+
}
1618+
16061619
match variant.as_str() {
1607-
"GetManifest" => Ok(CacherRequest::GetManifest),
16081620
"GetLogCacheContent" => {
16091621
let path = serde_json::from_value(value).map_err(de::Error::custom)?;
16101622
Ok(CacherRequest::GetLogCacheContent(path))
16111623
}
1612-
"GetStatus" => Ok(CacherRequest::GetStatus),
16131624
"GetLogsByRange" => {
16141625
let request = serde_json::from_value(value).map_err(de::Error::custom)?;
16151626
Ok(CacherRequest::GetLogsByRange(request))
16161627
}
1617-
"StartProviding" => Ok(CacherRequest::StartProviding),
1618-
"StopProviding" => Ok(CacherRequest::StopProviding),
16191628
"SetNodes" => {
16201629
let nodes = serde_json::from_value(value).map_err(de::Error::custom)?;
16211630
Ok(CacherRequest::SetNodes(nodes))
@@ -1641,7 +1650,7 @@ impl<'de> Deserialize<'de> for CacherRequest {
16411650
}
16421651
}
16431652

1644-
deserializer.deserialize_map(CacherRequestVisitor)
1653+
deserializer.deserialize_any(CacherRequestVisitor)
16451654
}
16461655
}
16471656

@@ -1681,16 +1690,8 @@ impl Serialize for CacherResponse {
16811690
map.serialize_entry("StopProviding", result)?;
16821691
map.end()
16831692
}
1684-
CacherResponse::Rejected => {
1685-
let mut map = serializer.serialize_map(Some(1))?;
1686-
map.serialize_entry("Rejected", &())?;
1687-
map.end()
1688-
}
1689-
CacherResponse::IsStarting => {
1690-
let mut map = serializer.serialize_map(Some(1))?;
1691-
map.serialize_entry("IsStarting", &())?;
1692-
map.end()
1693-
}
1693+
CacherResponse::Rejected => serializer.serialize_str("Rejected"),
1694+
CacherResponse::IsStarting => serializer.serialize_str("IsStarting"),
16941695
CacherResponse::SetNodes(result) => {
16951696
let mut map = serializer.serialize_map(Some(1))?;
16961697
map.serialize_entry("SetNodes", result)?;
@@ -1716,8 +1717,32 @@ impl<'de> Deserialize<'de> for CacherResponse {
17161717
type Value = CacherResponse;
17171718

17181719
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1719-
formatter
1720-
.write_str("a map with a single key representing the CacherResponse variant")
1720+
formatter.write_str("a string for unit variants or a map for other variants")
1721+
}
1722+
1723+
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
1724+
where
1725+
E: de::Error,
1726+
{
1727+
match value {
1728+
"Rejected" => Ok(CacherResponse::Rejected),
1729+
"IsStarting" => Ok(CacherResponse::IsStarting),
1730+
_ => Err(de::Error::unknown_variant(
1731+
value,
1732+
&[
1733+
"GetManifest",
1734+
"GetLogCacheContent",
1735+
"GetStatus",
1736+
"GetLogsByRange",
1737+
"StartProviding",
1738+
"StopProviding",
1739+
"Rejected",
1740+
"IsStarting",
1741+
"SetNodes",
1742+
"Reset",
1743+
],
1744+
)),
1745+
}
17211746
}
17221747

17231748
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
@@ -1728,6 +1753,11 @@ impl<'de> Deserialize<'de> for CacherResponse {
17281753
.next_entry::<String, serde_json::Value>()?
17291754
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
17301755

1756+
// Ensure there are no extra entries
1757+
if map.next_entry::<String, serde_json::Value>()?.is_some() {
1758+
return Err(de::Error::custom("unexpected extra entries in map"));
1759+
}
1760+
17311761
match variant.as_str() {
17321762
"GetManifest" => {
17331763
let manifest = serde_json::from_value(value).map_err(de::Error::custom)?;
@@ -1753,8 +1783,6 @@ impl<'de> Deserialize<'de> for CacherResponse {
17531783
let result = serde_json::from_value(value).map_err(de::Error::custom)?;
17541784
Ok(CacherResponse::StopProviding(result))
17551785
}
1756-
"Rejected" => Ok(CacherResponse::Rejected),
1757-
"IsStarting" => Ok(CacherResponse::IsStarting),
17581786
"SetNodes" => {
17591787
let result = serde_json::from_value(value).map_err(de::Error::custom)?;
17601788
Ok(CacherResponse::SetNodes(result))
@@ -1782,7 +1810,7 @@ impl<'de> Deserialize<'de> for CacherResponse {
17821810
}
17831811
}
17841812

1785-
deserializer.deserialize_map(CacherResponseVisitor)
1813+
deserializer.deserialize_any(CacherResponseVisitor)
17861814
}
17871815
}
17881816

src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@
1313
//! for applications that want to maximize composability and introspectability.
1414
//! For blobs, we recommend bincode to serialize and deserialize to bytes.
1515
//!
16+
//! `process_lib` v`2.x.y` uses [`wit-bindgen`](https://github.com/bytecodealliance/wit-bindgen) v`0.42.1`.
17+
//! Processes depending on `process_lib` must also use that version.
18+
//!
19+
//! `process_lib` version | `wit-bindgen` version
20+
//! --------------------- | ---------------------
21+
//! `2.x.y` | `0.42.1`
22+
//! `1.x.y` | `0.36.0`
23+
//!
1624
pub use crate::hyperware::process::standard::*;
1725
use serde_json::Value;
1826

0 commit comments

Comments
 (0)