feat: dial hints on the account-bound operations for self-resolving hosts

This commit is contained in:
randogoth 2026-09-29 12:48:40 +03:00
parent 5559fcce31
commit 28f13641a3
3 changed files with 45 additions and 23 deletions

View file

@ -56,6 +56,20 @@ impl Session {
/// Opens a session, enforcing sec 4's rule about unpinned servers. TCP pins
/// the server's Noise static key; on RNS the destination hash is the pin
/// (RNS.md sec 13.4).
/// The account address with the host's dial hint applied, when the caller
/// resolved DNS itself: account-bound operations re-read the account, so
/// the hint rides along this way rather than in the stored row.
#[cfg(feature = "store")]
fn account_with_dial(store: &Store, dial: Option<&str>) -> Result<Address, Error> {
let addr = store
.account()?
.ok_or(Error::NotRegistered)?;
Ok(match dial {
Some(dial) => addr.with_dial(dial),
None => addr,
})
}
#[cfg(feature = "store")]
pub fn connect(
store: &Store,
@ -286,9 +300,16 @@ pub enum Pushed {
/// An accept or a block only takes effect once the server holds the changed
/// set, so it is pushed now rather than at the next fetch.
#[cfg(feature = "store")]
pub fn push_tokens(store: &Store, account: &Account, timeout: u64) -> Result<Pushed, Error> {
let Some(addr) = store.account()? else {
return Ok(Pushed::NotRegistered);
pub fn push_tokens(
store: &Store,
account: &Account,
dial: Option<&str>,
timeout: u64,
) -> Result<Pushed, Error> {
let addr = match account_with_dial(store, dial) {
Ok(addr) => addr,
Err(Error::NotRegistered) => return Ok(Pushed::NotRegistered),
Err(e) => return Err(e),
};
let mut session = connect(store, &addr, true, timeout)?;
let held = authenticate(session.transport(), &addr.user, account, store)?;
@ -346,10 +367,13 @@ pub struct Rotated {
/// is untouched; only the index moves, and the superseded key stays
/// derivable from it (sec 2).
#[cfg(feature = "store")]
pub fn rotate(store: &Store, account: &Account, timeout: u64) -> Result<Rotated, Error> {
let Some(addr) = store.account()? else {
return Err(Error::NotRegistered);
};
pub fn rotate(
store: &Store,
account: &Account,
dial: Option<&str>,
timeout: u64,
) -> Result<Rotated, Error> {
let addr = account_with_dial(store, dial)?;
if account.index() as usize >= MAX_CHAIN {
return Err(Error::ChainLimit {
index: account.index() + 1,
@ -564,6 +588,9 @@ pub struct FetchOptions<'a> {
pub reset: bool,
/// Network timeout in seconds.
pub timeout: u64,
/// Dial this address instead of the account host, for hosts that
/// resolve DNS themselves; the host keeps its identity roles.
pub dial: Option<&'a str>,
/// Checked between pages and before each envelope; when raised,
/// `fetch_with` stops and returns the partial summary with `cancelled`
/// set. What was processed is accounted for locally — cursor moved or
@ -579,6 +606,7 @@ impl FetchOptions<'_> {
keep,
reset,
timeout,
dial: None,
cancel: None,
}
}
@ -607,9 +635,7 @@ pub fn fetch_with(
account: &Account,
opts: FetchOptions<'_>,
) -> Result<Fetched, Error> {
let Some(addr) = store.account()? else {
return Err(Error::NotRegistered);
};
let addr = account_with_dial(store, opts.dial)?;
if opts.reset {
store.set_cursor(0, &[0u8; ID_LEN])?;
}
@ -761,11 +787,10 @@ pub fn delete(
store: &Store,
account: &Account,
ids: &[[u8; ID_LEN]],
dial: Option<&str>,
timeout: u64,
) -> Result<u16, Error> {
let Some(addr) = store.account()? else {
return Err(Error::NotRegistered);
};
let addr = account_with_dial(store, dial)?;
let mut session = connect(store, &addr, true, timeout)?;
let transport = session.transport();
authenticate(transport, &addr.user, account, store)?;