#![allow(dead_code)]
#![allow(unexpected_cfgs)]
use prost::Message;
use saddle::ingress::{ProfuseGwCode, ProfuseGwContext, ProfuseGwResponse as Response};
use saddle::{BusinessConfig, application};
use serde::{Deserialize, Serialize};
use std::cell::Cell;
#[derive(Clone, PartialEq, Message, Deserialize)]
struct Input {}
#[derive(Deserialize)]
struct ParameterInput {
text: String,
json: String,
}
#[derive(Clone, PartialEq, Message)]
struct QueryBoundAccountsRequest {
#[prost(string, tag = "1")]
user_id: String,
}
#[derive(Clone, PartialEq, Message)]
struct QueryBoundAccountsResult {
#[prost(uint64, tag = "1")]
account_count: u64,
}
#[derive(Clone, PartialEq, Message, Serialize)]
struct Output {
#[prost(uint64, tag = "1")]
value: u64,
}
enum Code {
Failure,
}
impl ProfuseGwCode for Code {
const REGISTERED_CODES: &'static [&'static str] = &["FAILURE"];
fn stable_code(&self) -> &'static str {
"FAILURE"
}
}
saddle::database_operations! {
relational;
pub mod ops {
namespace "cf.account";
schema { account { id:u64, value:u64 } }
query Read { parameters ReadParams { id:u64 } from account as a;
where a.id==bind(id);result optional Row {value:a.value} }
update Write {parameters WriteParams {id:u64,value:u64} table account;
values {value:bind(value)} where account.id==bind(id);}
}
}
application! {
schema "saddle-application/2";
application App;
deployment_app "cf-app";
business_config ();
profusecontract { contract_dir "examples/contracts"; capability Cap; response_code Code; functions {
QueryBoundAccounts => query_bound_accounts { business_unit "puc"; function "查询用户绑定户号"; } (QueryBoundAccountsRequest)->QueryBoundAccountsResult;
} }
database_modules { Accounts {optional read(ops::Read);write store(ops::Write);} }
service ViaModule { ingress profusegw; operation_type "cf.module"; request Input; response Output;
handler module_handler; uses QueryBoundAccounts; database module db(Accounts); }
service ViaRoute { ingress profusegw; operation_type "cf.route"; request Input; response Output;
handler route_handler; database transaction transfer { optional read(ops::Read);write store(ops::Write); } }
service WaitRoute { ingress profusegw; operation_type "cf.wait"; request Input; response Output;
handler wait_handler; database transaction wait { optional read(ops::Read);write store(ops::Write); } }
service Parameters { ingress profusegw; operation_type "cf.parameters"; request ParameterInput; response Output;
handler parameter_handler; database module db(Accounts); }
}
async fn parameter_handler(
input: ParameterInput,
_: ProfuseGwContext,
mut cap: Cap<Parameters>,
_: BusinessConfig<()>,
) -> Response<Output, Code> {
let mut db = cap.db();
let text = db
.text(&input.text)
.await
.expect("same request Text construction");
assert_eq!(text.as_str(), input.text);
let value = match db.json(&input.json).await {
Ok(_) => 1,
Err(saddle::database::ParameterConstructionError::InvalidJson) => 0,
Err(error) => panic!("unexpected construction: {error:?}"),
};
Response::success(Output { value })
}
saddle::transaction_logic! {
fn module_logic(tx: Accounts; start:u64, state:Cell<u64>) -> (u64,()) {
for id in start..start+2 {
let step=tx.read(ops::ReadParams {id});
let row=step.await.map_err(|e| saddle::database::TransactionAbort::Technical(e.into_failure()))?;
if let Some(row)=row {state.set(row.value);}
tokio::task::yield_now().await;
tx.store(ops::WriteParams{id,value:state.get()+1}).await
.map_err(|e| saddle::database::TransactionAbort::Technical(e.into_failure()))?;
}
Ok(state.get())
}
}
saddle::transaction_logic! {
fn route_logic(tx: ViaRoute; state:Cell<u64>) -> (u64,()) {
let row=tx.read(ops::ReadParams{id:1}).await
.map_err(|e| saddle::database::TransactionAbort::Technical(e.into_failure()))?;
tokio::task::yield_now().await;
if let Some(row)=row {state.set(row.value);}
Ok(state.get())
}
}
saddle::transaction_logic! {
fn wait_logic(tx: WaitRoute;) -> (u64,()) {
let row=tx.read(ops::ReadParams{id:1}).await.map_err(|error|saddle::database::TransactionAbort::Technical(error.into_failure()))?.unwrap();
tx.store(ops::WriteParams{id:1,value:row.value+100}).await.map_err(|error|saddle::database::TransactionAbort::Technical(error.into_failure()))?;
println!("S_WAIT_ENTERED");
std::future::pending::<()>().await;
Ok(0)
}
}
async fn wait_handler(
_: Input,
_: ProfuseGwContext,
mut cap: Cap<WaitRoute>,
_: BusinessConfig<()>,
) -> Response<Output, Code> {
let _ = cap
.wait(
saddle::database::TransactionIsolation::RepeatableRead,
wait_logic(),
)
.await;
panic!("cancelled waiting transaction cannot return a successful handler");
}
fn accepts_actual_d<
B: saddle::transaction_construction::ReservedTransactionBody<
saddle::transaction_construction::Cancel,
>,
>(
_: B,
) {
}
async fn module_handler(
_: Input,
_: ProfuseGwContext,
mut cap: Cap<ViaModule>,
_: BusinessConfig<()>,
) -> Response<Output, Code> {
let value = {
let mut db = cap.db();
let _before = db
.read(ops::ReadParams { id: 1 })
.await
.expect("ordinary query succeeds");
match db
.transaction(
saddle::database::TransactionIsolation::RepeatableRead,
module_logic(1, Cell::new(0)),
)
.await
{
saddle::database::TransactionOutcome::Committed(value) => value,
other => panic!("module transaction must commit: {other:?}"),
}
};
match cap
.query_bound_accounts(QueryBoundAccountsRequest {
user_id: "test-user".into(),
})
.await
{
saddle::profusecontract::ExternalFunctionResult::TechnicalFailure(failure) => {
assert!(matches!(
failure.code(),
saddle::profusecontract::TechnicalFailureCode::DependencyUnavailable
| saddle::profusecontract::TechnicalFailureCode::TransportFailure
))
}
_ => panic!("owned closed loopback endpoint cannot return success"),
}
Response::success(Output { value })
}
async fn route_handler(
_: Input,
_: ProfuseGwContext,
mut cap: Cap<ViaRoute>,
_: BusinessConfig<()>,
) -> Response<Output, Code> {
match cap
.transfer(
saddle::database::TransactionIsolation::RepeatableRead,
route_logic(Cell::new(0)),
)
.await
{
saddle::database::TransactionOutcome::Committed(value) => {
Response::success(Output { value })
}
other => panic!("route transaction must commit: {other:?}"),
}
}
fn main() {
if std::env::args().any(|arg| arg == "--config") {
App::run().unwrap();
return;
}
println!(
"S_ENTRY_CURRENT {:?}",
saddle::__private::reserved_entry_layouts_for(&App::__execute_profusegw).unwrap()
);
let module = module_logic(1, Cell::new(0));
let route = route_logic(Cell::new(0));
let small = small_layout([0; 8]);
let large = large_layout([0; 4096]);
assert!(
__saddle_cf::body_layout::<Accounts, _>(&large).size()
> __saddle_cf::body_layout::<Accounts, _>(&small).size() + 4000
);
println!("S_LAYOUT_VARIATION_PASS before_execute no_session");
println!(
"S actual D body module={:?} route={:?}",
__saddle_cf::body_layout::<Accounts, _>(&module),
__saddle_cf::body_layout::<ViaRoute, _>(&route)
);
println!(
"S layout mode only; live entry/SQL/cancellation evidence is produced by run-database.sh"
);
for (name, (_, layout)) in saddle_core::request_context::request_context_layouts()
.into_iter()
.enumerate()
{
println!(
"S_CORE_DYNAMIC {name} bytes={} align={}",
layout.size(),
layout.align()
);
}
for (name, layout) in saddle_runtime::request_task::reserved::supervised_scope_layouts() {
println!(
"S_SCOPE_DYNAMIC {name} bytes={} align={}",
layout.size(),
layout.align()
);
}
println!(
"S_INLINE_X attempt={} delivery={} (already in enclosing body; no double charge)",
std::mem::size_of::<saddle_boundary::reserved_diagnostics::ReservedAttempt<'static>>(),
std::mem::size_of::<saddle_boundary::reserved_diagnostics::ReservedDelivery<'static>>()
);
let (stream, cycle, _) = saddle_observability::root_diagnostic::original_capture_layout();
let logging = saddle_observability::root_diagnostic::request_logging_layouts();
println!(
"S_LOG_DOMAIN stream={} cycle={} frame={} packet={} slots={}; source synchronous stack != retained task heap; queue remains existing log domain",
stream.size(),
cycle.size(),
logging.source_frame.size(),
logging.emergency_packet.size(),
logging.emergency_slots
);
}
saddle::transaction_logic! {
fn small_layout(_tx:Accounts; bytes:[u8;8])->(u64,()) {
tokio::task::yield_now().await;
Ok(std::hint::black_box(bytes)[0] as u64)
}
}
saddle::transaction_logic! {
fn large_layout(_tx:Accounts; bytes:[u8;4096])->(u64,()) {
tokio::task::yield_now().await;
Ok(std::hint::black_box(bytes)[0] as u64)
}
}
#[cfg(cf_non_send)]
saddle::transaction_logic! {
fn forbidden_send(_tx:Accounts; value:std::rc::Rc<u64>)->(u64,()) {
tokio::task::yield_now().await; Ok(*value)
}
}
#[cfg(cf_undeclared)]
saddle::transaction_logic! {
fn forbidden_operation(tx:Accounts;)->(u64,()) {
tx.not_declared().await; Ok(0)
}
}
#[cfg(cf_escape)]
saddle::transaction_logic! {
fn forbidden_escape(tx:Accounts;)->(&'static str,()) {
tokio::spawn(async move {tx.read(ops::ReadParams{id:1}).await}); Ok("no")
}
}