implement more models and rhai examples
This commit is contained in:
317
heromodels/src/models/finance/rhai.rs
Normal file
317
heromodels/src/models/finance/rhai.rs
Normal file
@@ -0,0 +1,317 @@
|
||||
use rhai::{Engine, Array, ImmutableString, INT, EvalAltResult};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use chrono::Utc;
|
||||
|
||||
use adapter_macros::register_rhai_enum_accessors;
|
||||
use adapter_macros::register_rhai_datetime_accessors;
|
||||
use adapter_macros::register_rhai_vec_string_accessors;
|
||||
use adapter_macros::rhai_timestamp_helpers;
|
||||
|
||||
use crate::models::finance::account::Account;
|
||||
use crate::models::finance::asset::{Asset, AssetType};
|
||||
use crate::models::finance::marketplace::{Listing, Bid, ListingStatus, ListingType, BidStatus};
|
||||
|
||||
// --- Enum to String & String to Enum Helper Functions (domain-specific) ---
|
||||
// These remain here as they are specific to the finance models' enums.
|
||||
|
||||
fn asset_type_to_string(asset_type: &AssetType) -> ImmutableString {
|
||||
format!("{:?}", asset_type).into()
|
||||
}
|
||||
fn string_to_asset_type(s: &str) -> Result<AssetType, Box<EvalAltResult>> {
|
||||
match s {
|
||||
"Erc20" => Ok(AssetType::Erc20),
|
||||
"Erc721" => Ok(AssetType::Erc721),
|
||||
"Erc1155" => Ok(AssetType::Erc1155),
|
||||
"Native" => Ok(AssetType::Native),
|
||||
_ => Err(format!("Invalid AssetType string: {}", s).into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn listing_status_to_string(status: &ListingStatus) -> ImmutableString {
|
||||
format!("{:?}", status).into()
|
||||
}
|
||||
fn string_to_listing_status(s: &str) -> Result<ListingStatus, Box<EvalAltResult>> {
|
||||
match s.to_lowercase().as_str() {
|
||||
"active" => Ok(ListingStatus::Active),
|
||||
"sold" => Ok(ListingStatus::Sold),
|
||||
"cancelled" => Ok(ListingStatus::Cancelled),
|
||||
"expired" => Ok(ListingStatus::Expired),
|
||||
_ => Err(format!("Invalid ListingStatus string: {}", s).into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn listing_type_to_string(lt: &ListingType) -> ImmutableString {
|
||||
format!("{:?}", lt).into()
|
||||
}
|
||||
fn string_to_listing_type(s: &str) -> Result<ListingType, Box<EvalAltResult>> {
|
||||
match s.to_lowercase().as_str() {
|
||||
"fixedprice" => Ok(ListingType::FixedPrice),
|
||||
"auction" => Ok(ListingType::Auction),
|
||||
"exchange" => Ok(ListingType::Exchange),
|
||||
_ => Err(format!("Invalid ListingType string: {}", s).into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn bid_status_to_string(status: &BidStatus) -> ImmutableString {
|
||||
format!("{:?}", status).into()
|
||||
}
|
||||
fn string_to_bid_status(s: &str) -> Result<BidStatus, Box<EvalAltResult>> {
|
||||
match s.to_lowercase().as_str() {
|
||||
"active" => Ok(BidStatus::Active),
|
||||
"accepted" => Ok(BidStatus::Accepted),
|
||||
"rejected" => Ok(BidStatus::Rejected),
|
||||
"cancelled" => Ok(BidStatus::Cancelled),
|
||||
_ => Err(format!("Invalid BidStatus string: {}", s).into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn register_rhai_engine_functions(
|
||||
engine: &mut Engine,
|
||||
db_accounts: Arc<Mutex<HashMap<u32, Account>>>,
|
||||
db_assets: Arc<Mutex<HashMap<u32, Asset>>>,
|
||||
db_listings: Arc<Mutex<HashMap<u32, Listing>>>,
|
||||
) {
|
||||
// --- Account model ---
|
||||
engine.build_type::<Account>()
|
||||
.register_fn("new_account",
|
||||
|id_rhai: INT, name_rhai: ImmutableString, user_id_rhai: INT, desc_rhai: ImmutableString, ledger_rhai: ImmutableString, addr_rhai: ImmutableString, pubkey_rhai: ImmutableString| -> Account {
|
||||
Account::new(id_rhai as u32, name_rhai, user_id_rhai as u32, desc_rhai, ledger_rhai, addr_rhai, pubkey_rhai)
|
||||
}
|
||||
)
|
||||
.register_get_set("name",
|
||||
|obj: &mut Account| -> ImmutableString { obj.name.clone().into() },
|
||||
|obj: &mut Account, val: ImmutableString| obj.name = val.to_string()
|
||||
)
|
||||
.register_get_set("user_id",
|
||||
|obj: &mut Account| obj.user_id as INT,
|
||||
|obj: &mut Account, val: INT| obj.user_id = val as u32
|
||||
)
|
||||
.register_get_set("description",
|
||||
|obj: &mut Account| -> ImmutableString { obj.description.clone().into() },
|
||||
|obj: &mut Account, val: ImmutableString| obj.description = val.to_string()
|
||||
)
|
||||
.register_get_set("ledger",
|
||||
|obj: &mut Account| -> ImmutableString { obj.ledger.clone().into() },
|
||||
|obj: &mut Account, val: ImmutableString| obj.ledger = val.to_string()
|
||||
)
|
||||
.register_get_set("address",
|
||||
|obj: &mut Account| -> ImmutableString { obj.address.clone().into() },
|
||||
|obj: &mut Account, val: ImmutableString| obj.address = val.to_string()
|
||||
)
|
||||
.register_get_set("pubkey",
|
||||
|obj: &mut Account| -> ImmutableString { obj.pubkey.clone().into() },
|
||||
|obj: &mut Account, val: ImmutableString| obj.pubkey = val.to_string()
|
||||
)
|
||||
.register_get("created_at_ts", |obj: &mut Account| obj.base_data.created_at);
|
||||
engine.register_get("assets_list", |acc: &mut Account| -> Array {
|
||||
acc.assets.iter().cloned().map(rhai::Dynamic::from).collect()
|
||||
});
|
||||
|
||||
// --- Asset model ---
|
||||
engine.build_type::<Asset>()
|
||||
.register_fn("new_asset",
|
||||
|id_rhai: INT, name: ImmutableString, description: ImmutableString, amount: f64, address: ImmutableString, asset_type_str_rhai: ImmutableString, decimals_rhai: INT| -> Result<Asset, Box<EvalAltResult>> {
|
||||
let asset_type = self::string_to_asset_type(asset_type_str_rhai.as_str())?;
|
||||
Ok(Asset::new(id_rhai as u32, name, description, amount, address, asset_type, decimals_rhai as u8))
|
||||
}
|
||||
)
|
||||
.register_get("id", |asset: &mut Asset| asset.base_data.id as INT)
|
||||
.register_get_set("name",
|
||||
|asset: &mut Asset| -> ImmutableString { asset.name.clone().into() },
|
||||
|asset: &mut Asset, val: ImmutableString| asset.name = val.to_string()
|
||||
)
|
||||
.register_get_set("description",
|
||||
|asset: &mut Asset| -> ImmutableString { asset.description.clone().into() },
|
||||
|asset: &mut Asset, val: ImmutableString| asset.description = val.to_string()
|
||||
)
|
||||
.register_get_set("amount", |asset: &mut Asset| asset.amount, |asset: &mut Asset, amount_val: f64| asset.amount = amount_val)
|
||||
.register_get_set("address",
|
||||
|asset: &mut Asset| -> ImmutableString { asset.address.clone().into() },
|
||||
|asset: &mut Asset, val: ImmutableString| asset.address = val.to_string()
|
||||
)
|
||||
.register_get("decimals", |asset: &mut Asset| asset.decimals as INT)
|
||||
.register_get("created_at_ts", |obj: &mut Asset| obj.base_data.created_at);
|
||||
register_rhai_enum_accessors!(engine, Asset, asset_type, "asset_type_str", self::asset_type_to_string, self::string_to_asset_type);
|
||||
|
||||
// --- Bid model ---
|
||||
engine.register_type_with_name::<Bid>("Bid")
|
||||
.register_fn("new_bid",
|
||||
|listing_id_rhai: ImmutableString, bidder_id_rhai: INT, amount_rhai: f64, currency_rhai: ImmutableString| -> Bid {
|
||||
Bid::new(listing_id_rhai, bidder_id_rhai as u32, amount_rhai, currency_rhai)
|
||||
}
|
||||
)
|
||||
.register_get_set("listing_id",
|
||||
|bid: &mut Bid| -> ImmutableString { bid.listing_id.clone().into() },
|
||||
|bid: &mut Bid, val: ImmutableString| bid.listing_id = val.to_string()
|
||||
)
|
||||
.register_get_set("bidder_id", |bid: &mut Bid| bid.bidder_id as INT, |bid: &mut Bid, val: INT| bid.bidder_id = val as u32)
|
||||
.register_get_set("amount", |bid: &mut Bid| bid.amount, |bid: &mut Bid, val: f64| bid.amount = val)
|
||||
.register_get_set("currency",
|
||||
|bid: &mut Bid| -> ImmutableString { bid.currency.clone().into() },
|
||||
|bid: &mut Bid, val: ImmutableString| bid.currency = val.to_string()
|
||||
);
|
||||
register_rhai_enum_accessors!(engine, Bid, status, "status_str", self::bid_status_to_string, self::string_to_bid_status);
|
||||
register_rhai_datetime_accessors!(engine, Bid, created_at, "created_at_ts", _required);
|
||||
engine.register_fn("update_bid_status_script",
|
||||
|bid: Bid, status_str_rhai: ImmutableString| -> Result<Bid, Box<EvalAltResult>> {
|
||||
let status = self::string_to_bid_status(status_str_rhai.as_str())?;
|
||||
let updated_bid = bid.update_status(status);
|
||||
Ok(updated_bid)
|
||||
}
|
||||
);
|
||||
|
||||
// --- Listing --- (id is u32)
|
||||
engine.register_type_with_name::<Listing>("Listing")
|
||||
.register_fn("new_listing",
|
||||
|id_rhai: INT, title_rhai: ImmutableString, description_rhai: ImmutableString,
|
||||
asset_id_rhai: ImmutableString, asset_type_str_rhai: ImmutableString, seller_id_rhai: ImmutableString,
|
||||
price_rhai: f64, currency_rhai: ImmutableString, listing_type_str_rhai: ImmutableString,
|
||||
expires_at_ts_opt_rhai: Option<INT>, tags_dyn_rhai: Array, image_url_opt_rhai: Option<ImmutableString>|
|
||||
-> Result<Listing, Box<EvalAltResult>> {
|
||||
|
||||
let asset_type = self::string_to_asset_type(asset_type_str_rhai.as_str())?;
|
||||
let listing_type = self::string_to_listing_type(listing_type_str_rhai.as_str())?;
|
||||
let expires_at = rhai_timestamp_helpers::option_rhai_timestamp_to_datetime(expires_at_ts_opt_rhai)?;
|
||||
|
||||
let tags = tags_dyn_rhai.into_iter().map(|d| d.into_string().unwrap_or_default()).collect();
|
||||
let image_url = image_url_opt_rhai.map(|s| s.to_string());
|
||||
|
||||
Ok(Listing::new(
|
||||
id_rhai as u32, title_rhai, description_rhai, asset_id_rhai,
|
||||
asset_type, seller_id_rhai, price_rhai, currency_rhai, listing_type,
|
||||
expires_at, tags, image_url
|
||||
))
|
||||
}
|
||||
)
|
||||
.register_get("id", |l: &mut Listing| l.base_data.id as INT)
|
||||
.register_get_set("title",
|
||||
|l: &mut Listing| -> ImmutableString { l.title.clone().into() },
|
||||
|l: &mut Listing, v: ImmutableString| l.title = v.to_string()
|
||||
)
|
||||
.register_get_set("description",
|
||||
|l: &mut Listing| -> ImmutableString { l.description.clone().into() },
|
||||
|l: &mut Listing, v: ImmutableString| l.description = v.to_string()
|
||||
)
|
||||
.register_get_set("asset_id",
|
||||
|l: &mut Listing| -> ImmutableString { l.asset_id.clone().into() },
|
||||
|l: &mut Listing, v: ImmutableString| l.asset_id = v.to_string()
|
||||
)
|
||||
.register_get_set("seller_id",
|
||||
|l: &mut Listing| -> ImmutableString { l.seller_id.clone().into() },
|
||||
|l: &mut Listing, v: ImmutableString| l.seller_id = v.to_string()
|
||||
)
|
||||
.register_get_set("price", |l: &mut Listing| l.price, |l: &mut Listing, v: f64| l.price = v)
|
||||
.register_get_set("currency",
|
||||
|l: &mut Listing| -> ImmutableString { l.currency.clone().into() },
|
||||
|l: &mut Listing, v: ImmutableString| l.currency = v.to_string()
|
||||
)
|
||||
.register_get_set("buyer_id",
|
||||
|l: &mut Listing| -> Option<ImmutableString> { l.buyer_id.clone().map(ImmutableString::from) },
|
||||
|l: &mut Listing, v_opt: Option<ImmutableString>| l.buyer_id = v_opt.map(|s| s.to_string())
|
||||
)
|
||||
.register_get_set("sale_price",
|
||||
|l: &mut Listing| -> Option<f64> { l.sale_price },
|
||||
|l: &mut Listing, v_opt: Option<f64>| l.sale_price = v_opt
|
||||
)
|
||||
.register_get_set("image_url",
|
||||
|l: &mut Listing| -> Option<ImmutableString> { l.image_url.clone().map(ImmutableString::from) },
|
||||
|l: &mut Listing, v: Option<ImmutableString>| l.image_url = v.map(|s| s.to_string())
|
||||
)
|
||||
.register_get("created_at_ts", |obj: &mut Listing| obj.base_data.created_at);
|
||||
|
||||
register_rhai_enum_accessors!(engine, Listing, listing_type, "listing_type_str", self::listing_type_to_string, self::string_to_listing_type);
|
||||
register_rhai_enum_accessors!(engine, Listing, status, "status_str", self::listing_status_to_string, self::string_to_listing_status);
|
||||
register_rhai_enum_accessors!(engine, Listing, asset_type, "asset_type_str_listing", self::asset_type_to_string, self::string_to_asset_type);
|
||||
|
||||
register_rhai_datetime_accessors!(engine, Listing, expires_at, "expires_at_ts_opt");
|
||||
register_rhai_datetime_accessors!(engine, Listing, sold_at, "sold_at_ts_opt");
|
||||
|
||||
register_rhai_vec_string_accessors!(engine, Listing, tags, "tags_cloned");
|
||||
|
||||
engine.register_fn("add_listing_bid",
|
||||
|listing: Listing, bid: Bid| -> Result<Listing, Box<EvalAltResult>> {
|
||||
listing.add_bid(bid).map_err(|e| e.into())
|
||||
}
|
||||
);
|
||||
engine.register_fn("get_bids_cloned", |listing: &mut Listing| listing.bids.clone());
|
||||
engine.register_fn("complete_listing_sale_script",
|
||||
|listing: Listing, buyer_id_rhai: ImmutableString, sale_price_rhai: f64| -> Result<Listing, Box<EvalAltResult>> {
|
||||
listing.complete_sale(buyer_id_rhai.as_str(), sale_price_rhai).map_err(|e| e.into())
|
||||
}
|
||||
);
|
||||
engine.register_fn("cancel_listing_script",
|
||||
|listing: Listing| -> Result<Listing, Box<EvalAltResult>> {
|
||||
listing.cancel().map_err(|e| e.into())
|
||||
}
|
||||
);
|
||||
engine.register_fn("add_listing_tags_script",
|
||||
|listing: Listing, tags_dyn_rhai: Array| -> Result<Listing, Box<EvalAltResult>> {
|
||||
let tags_to_add: Vec<String> = tags_dyn_rhai.into_iter().map(|d| d.into_string().unwrap_or_default()).collect();
|
||||
Ok(listing.add_tags(tags_to_add))
|
||||
}
|
||||
);
|
||||
|
||||
// --- Global Helper Functions (Enum conversions, potentially already covered by macros but good for direct script use) ---
|
||||
// These are useful if scripts need to convert strings to enums outside of object setters.
|
||||
engine.register_fn("str_to_asset_type", |s: ImmutableString| self::string_to_asset_type(s.as_str()));
|
||||
engine.register_fn("asset_type_to_str", self::asset_type_to_string);
|
||||
engine.register_fn("str_to_listing_status", |s: ImmutableString| self::string_to_listing_status(s.as_str()));
|
||||
engine.register_fn("listing_status_to_str", self::listing_status_to_string);
|
||||
engine.register_fn("str_to_listing_type", |s: ImmutableString| self::string_to_listing_type(s.as_str()));
|
||||
engine.register_fn("listing_type_to_str", self::listing_type_to_string);
|
||||
engine.register_fn("str_to_bid_status", |s: ImmutableString| self::string_to_bid_status(s.as_str()));
|
||||
engine.register_fn("bid_status_to_str", self::bid_status_to_string);
|
||||
|
||||
|
||||
// --- Mock DB functions ---
|
||||
let accounts_db_clone = Arc::clone(&db_accounts);
|
||||
engine.register_fn("set_account", move |account: Account| {
|
||||
let mut db = accounts_db_clone.lock().unwrap();
|
||||
db.insert(account.base_data.id, account);
|
||||
});
|
||||
|
||||
let accounts_db_clone_get = Arc::clone(&db_accounts);
|
||||
engine.register_fn("get_account_by_id", move |id_rhai: INT| -> Result<Account, Box<EvalAltResult>> {
|
||||
let db = accounts_db_clone_get.lock().unwrap();
|
||||
match db.get(&(id_rhai as u32)) {
|
||||
Some(account) => Ok(account.clone()),
|
||||
None => Err(format!("Account not found with ID: {}", id_rhai).into()),
|
||||
}
|
||||
});
|
||||
|
||||
let assets_db_clone = Arc::clone(&db_assets);
|
||||
engine.register_fn("set_asset", move |asset: Asset| {
|
||||
let mut db = assets_db_clone.lock().unwrap();
|
||||
db.insert(asset.base_data.id, asset);
|
||||
});
|
||||
|
||||
let assets_db_clone_get = Arc::clone(&db_assets);
|
||||
engine.register_fn("get_asset_by_id", move |id_rhai: INT| -> Result<Asset, Box<EvalAltResult>> {
|
||||
let db = assets_db_clone_get.lock().unwrap();
|
||||
match db.get(&(id_rhai as u32)) {
|
||||
Some(asset) => Ok(asset.clone()),
|
||||
None => Err(format!("Asset not found with ID: {}", id_rhai).into()),
|
||||
}
|
||||
});
|
||||
|
||||
let listings_db_clone = Arc::clone(&db_listings);
|
||||
engine.register_fn("set_listing", move |listing: Listing| {
|
||||
let mut db = listings_db_clone.lock().unwrap();
|
||||
db.insert(listing.base_data.id, listing);
|
||||
});
|
||||
|
||||
let listings_db_clone_get = Arc::clone(&db_listings);
|
||||
engine.register_fn("get_listing_by_id", move |id_rhai: INT| -> Result<Listing, Box<EvalAltResult>> {
|
||||
let db = listings_db_clone_get.lock().unwrap();
|
||||
match db.get(&(id_rhai as u32)) {
|
||||
Some(listing) => Ok(listing.clone()),
|
||||
None => Err(format!("Listing not found with ID: {}", id_rhai).into()),
|
||||
}
|
||||
});
|
||||
|
||||
// Global timestamp function for scripts to get current time
|
||||
engine.register_fn("timestamp", || Utc::now().timestamp());
|
||||
}
|
Reference in New Issue
Block a user