Skip to content

Commit

Permalink
feat: parse the routes from sui + correct summarization
Browse files Browse the repository at this point in the history
Signed-off-by: giac-mysten <[email protected]>
  • Loading branch information
giac-mysten committed Oct 7, 2024
1 parent 57fb4bd commit f04754c
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 23 deletions.
4 changes: 1 addition & 3 deletions examples/snake/ws-resources.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
}
},
"routes": {
"/path/*": "/index.html",
"/some/other/path/*": "/index.html",
"/test/*": "/index.html"
"/path/*": "/index.html"
}
}
1 change: 1 addition & 0 deletions site-builder/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod display;
mod preprocessor;
mod publish;
mod site;
mod summary;
mod util;
mod walrus;
use std::path::PathBuf;
Expand Down
9 changes: 5 additions & 4 deletions site-builder/src/publish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ use crate::{
site::{
config::WSResources,
manager::{SiteIdentifier, SiteManager},
resource::{OperationsSummary, ResourceManager},
resource::ResourceManager,
},
summary::{SiteDataDiffSummary, Summarizable},
util::{
get_site_id_from_response,
id_to_base36,
Expand Down Expand Up @@ -145,7 +146,7 @@ impl SiteEditor {

async fn run_single_edit(
&self,
) -> Result<(SuiAddress, SuiTransactionBlockResponse, OperationsSummary)> {
) -> Result<(SuiAddress, SuiTransactionBlockResponse, SiteDataDiffSummary)> {
if self.publish_options.list_directory {
display::action(format!("Preprocessing: {}", self.directory().display()));
Preprocessor::preprocess(self.directory())?;
Expand Down Expand Up @@ -233,7 +234,7 @@ fn print_summary(
address: &SuiAddress,
site_id: &SiteIdentifier,
response: &SuiTransactionBlockResponse,
summary: &OperationsSummary,
summary: &impl Summarizable,
) -> Result<()> {
if let Some(SuiTransactionBlockEffects::V1(eff)) = response.effects.as_ref() {
if let SuiExecutionStatus::Failure { error } = &eff.status {
Expand All @@ -245,7 +246,7 @@ fn print_summary(
}

display::header("Execution completed");
println!("{}\n", summary);
println!("{}\n", summary.to_summary());
let object_id = match site_id {
SiteIdentifier::ExistingSite(id) => {
println!("Site object ID: {}", id);
Expand Down
47 changes: 40 additions & 7 deletions site-builder/src/site.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@ use std::{
};

use anyhow::{anyhow, Result};
use resource::{ResourceInfo, ResourceOp, ResourceSet};
use resource::{MapWrapper, ResourceInfo, ResourceOp, ResourceSet};
use serde::{Deserialize, Serialize};
use sui_sdk::{
rpc_types::{SuiMoveValue, SuiObjectDataOptions},
rpc_types::{SuiMoveStruct, SuiMoveValue, SuiObjectDataOptions},
SuiClient,
};
use sui_types::{base_types::ObjectID, dynamic_field::DynamicFieldInfo, TypeTag};
use sui_types::{
base_types::ObjectID,
dynamic_field::{DynamicFieldInfo, DynamicFieldName},
TypeTag,
};

use crate::util::{get_struct_from_object_response, handle_pagination};

Expand Down Expand Up @@ -51,6 +55,16 @@ impl Routes {
}
}

impl TryFrom<SuiMoveStruct> for Routes {
type Error = anyhow::Error;

fn try_from(source: SuiMoveStruct) -> Result<Self, Self::Error> {
let routes: MapWrapper =
get_dynamic_field!(source, "route_list", SuiMoveValue::Struct)?.try_into()?;
Ok(Self(routes.0))
}
}

#[derive(Debug, Clone)]
pub enum RouteOps {
Unchanged,
Expand Down Expand Up @@ -143,24 +157,43 @@ impl RemoteSiteFactory<'_> {
/// Gets the remote site representation stored on chain
pub async fn get_from_chain(&self, site_id: ObjectID) -> Result<SiteData> {
let dynamic_fields = self.get_all_dynamic_field_info(site_id).await?;
let resource_ids = self.resources_from_dynamic_fields(dynamic_fields)?;
let resource_ids = self.resources_from_dynamic_fields(&dynamic_fields)?;
let resources = futures::future::try_join_all(
resource_ids
.into_values()
.map(|id| self.get_remote_resource_info(id)),
)
.await?;
let routes = self.get_routes(site_id).await?;

Ok(SiteData {
resources: ResourceSet::from_iter(resources),
routes: None,
routes,
})
}

async fn get_routes(&self, site_id: ObjectID) -> Result<Option<Routes>> {
let response = self
.sui_client
.read_api()
.get_dynamic_field_object(
site_id,
DynamicFieldName {
type_: TypeTag::Vector(Box::new(TypeTag::U8)),
value: "routes".into(),
},
)
.await?;
let dynamic_field = get_struct_from_object_response(&response)?;
let routes =
get_dynamic_field!(dynamic_field, "value", SuiMoveValue::Struct)?.try_into()?;
Ok(Some(routes))
}

/// Gets all the resources and their object ids from chain.
pub async fn get_existing_resources(&self) -> Result<HashMap<String, ObjectID>> {
let dynamic_fields = self.get_all_dynamic_field_info(self.package_id).await?;
self.resources_from_dynamic_fields(dynamic_fields)
self.resources_from_dynamic_fields(&dynamic_fields)
}

async fn get_all_dynamic_field_info(
Expand Down Expand Up @@ -192,7 +225,7 @@ impl RemoteSiteFactory<'_> {
/// Filters the dynamic fields to get the resource object IDs.
fn resources_from_dynamic_fields(
&self,
dynamic_fields: Vec<DynamicFieldInfo>,
dynamic_fields: &[DynamicFieldInfo],
) -> Result<HashMap<String, ObjectID>> {
let type_tag = self.resource_path_tag();
Ok(dynamic_fields
Expand Down
20 changes: 11 additions & 9 deletions site-builder/src/site/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,19 @@ use sui_types::{

use super::{
builder::SitePtb,
resource::{OperationsSummary, ResourceOp},
resource::ResourceOp,
RemoteSiteFactory,
SiteData,
SiteDataDiff,
SITE_MODULE,
};
use crate::{display, publish::WhenWalrusUpload, walrus::Walrus, Config};
use crate::{
display,
publish::WhenWalrusUpload,
summary::SiteDataDiffSummary,
walrus::Walrus,
Config,
};

/// The identifier for the new or existing site.
///
Expand Down Expand Up @@ -67,7 +73,7 @@ impl SiteManager {
pub async fn update_site(
&self,
local_site_data: &SiteData,
) -> Result<(SuiTransactionBlockResponse, OperationsSummary)> {
) -> Result<(SuiTransactionBlockResponse, SiteDataDiffSummary)> {
let existing_site = match &self.site_id {
SiteIdentifier::ExistingSite(site_id) => {
RemoteSiteFactory::new(&self.sui_client().await?, self.config.package)
Expand All @@ -90,13 +96,9 @@ impl SiteManager {
display::action("Updating the Walrus Site object on Sui");
let result = self.execute_sui_updates(&site_updates).await?;
display::done();
return Ok((result, site_updates.resource_ops.into()));
return Ok((result, site_updates.into()));
}
// TODO(giac) improve this return
Ok((
SuiTransactionBlockResponse::default(),
site_updates.resource_ops.into(),
))
Ok((SuiTransactionBlockResponse::default(), site_updates.into()))
}

/// Publishes the resources to Walrus.
Expand Down
11 changes: 11 additions & 0 deletions site-builder/src/site/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ pub struct HttpHeaders(pub BTreeMap<String, String>);
impl TryFrom<SuiMoveStruct> for HttpHeaders {
type Error = anyhow::Error;

fn try_from(source: SuiMoveStruct) -> Result<Self, Self::Error> {
let map = MapWrapper::try_from(source)?;
Ok(Self(map.0))
}
}

pub struct MapWrapper(pub BTreeMap<String, String>);

impl TryFrom<SuiMoveStruct> for MapWrapper {
type Error = anyhow::Error;

fn try_from(source: SuiMoveStruct) -> Result<Self, Self::Error> {
let contents: Vec<_> = get_dynamic_field!(source, "contents", SuiMoveValue::Vector)?;
let mut headers = BTreeMap::new();
Expand Down
102 changes: 102 additions & 0 deletions site-builder/src/summary.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

//! Summaries of the run results.

use crate::{
site::{resource::ResourceOp, RouteOps, SiteDataDiff},
walrus::types::BlobId,
};

/// The struct can be turned into a summary.
pub trait Summarizable {
fn to_summary(&self) -> String;
}

pub struct ResourceOpSummary {
operation: String,
path: String,
blob_id: BlobId,
}

impl From<&ResourceOp<'_>> for ResourceOpSummary {
fn from(value: &ResourceOp<'_>) -> Self {
let (operation, info) = match value {
ResourceOp::Deleted(resource) => ("deleted".to_owned(), &resource.info),
ResourceOp::Created(resource) => ("created".to_owned(), &resource.info),
};
ResourceOpSummary {
operation,
path: info.path.clone(),
blob_id: info.blob_id,
}
}
}

impl Summarizable for ResourceOpSummary {
fn to_summary(&self) -> String {
format!(
"{} resource {} with blob ID {}",
self.operation, self.path, self.blob_id
)
}
}

impl Summarizable for RouteOps {
fn to_summary(&self) -> String {
match self {
RouteOps::Unchanged => "The site routes were left unchanged".to_owned(),
RouteOps::Replace(_) => "The site routes were modified".to_owned(),
}
}
}

impl Summarizable for Vec<ResourceOpSummary> {
fn to_summary(&self) -> String {
self.iter()
.map(|op| format!(" - {}", op.to_summary()))
.collect::<Vec<_>>()
.join("\n")
.to_owned()
}
}

pub struct SiteDataDiffSummary {
resource_ops: Vec<ResourceOpSummary>,
route_ops: RouteOps,
}

impl From<&SiteDataDiff<'_>> for SiteDataDiffSummary {
fn from(value: &SiteDataDiff<'_>) -> Self {
SiteDataDiffSummary {
resource_ops: value.resource_ops.iter().map(|op| op.into()).collect(),
route_ops: value.route_ops.clone(),
}
}
}

impl From<SiteDataDiff<'_>> for SiteDataDiffSummary {
fn from(value: SiteDataDiff<'_>) -> Self {
(&value).into()
}
}

impl Summarizable for SiteDataDiffSummary {
fn to_summary(&self) -> String {
if self.resource_ops.is_empty() && self.route_ops.is_unchanged() {
return "No operation needs to be performed".to_owned();
}

let resource_str = if !self.resource_ops.is_empty() {
format!(
"Resource operations performed:\n{}\n",
self.resource_ops.to_summary()
)
} else {
"".to_owned()
};
let route_str = self.route_ops.to_summary();

format!("{}{}", resource_str, route_str)
}
}

0 comments on commit f04754c

Please sign in to comment.