Cross-app calls
Task: have one app tell, or ask, another app in the same organization.
The protocol side, delivery order, dead letters and the node’s checks, is in Cross-app calls.
1. Admit the caller
Section titled “1. Admit the caller”A method is reachable from another app only if it says so:
/// Records a ping from the app `from`; only `pinger` may call it.#[app::allow(app = "pinger")]pub fn pong(&mut self, from: String) -> app::Result<()> { let env::Caller::App(origin) = env::caller() else { return Err(AppError::forbidden()); }; self.pings.insert(&origin, &from)?; Ok(())}#[app::allow(app = "<app id>")] admits one app; allow(app = "*") admits any
app the node delivers from. The node refuses every other app. Inside the method,
env::caller() is Caller::App(<id>), set by the node, so it cannot be forged:
use it, not an argument, to know who called.
2. Send a message
Section titled “2. Send a message”pub fn ping(&mut self, target: String) -> app::Result<()> { let args = std::collections::BTreeMap::from([("from", env::app_id())]); env::xcall(&target, "pong", &args)?; Ok(())}args is any serde value, sent as the JSON arguments a client would send.
env::xcall(app, method, &args) queues the message in this run’s outbox. The
node delivers it after the entry commits, only if the run succeeds, at least
once and in order per sending app. The target must be in the same organization
(or have the same owner). A run may queue at most 100.
3. Call and read synchronously
Section titled “3. Call and read synchronously”let args = std::collections::BTreeMap::from([("account", account)]);// A u64 result arrives as a decimal string, like every u64 on the wire.let balance: String = env::xcall_view("ledger", "balance", &args)?;env::xcall_call::<T>(app, method, &args) and env::xcall_view::<T>(..) run
the target now and decode its JSON result as T. A failure is AppError
XcallFailed, carrying the target’s error. Messages, calls and views all reach
only methods that allow this app.
Test it
Section titled “Test it”TestApp keeps the messages a run sent: take_xcalls() returns them and
deliver(..) runs one against another TestApp; mock_app(..) stands in for
the target of a synchronous call (Testing).