~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/atlibs-socialweb-computer-requester

socialweb.computer market requester and policy modules for atlibs, with its web pages and lexicons

0
0
main
84 lines · 3.3 KB Raw History
// The contract's last step: find the signals `signal` wrote for its receipt (a webrtc.connect
// shell, a webrtc:// fetch to a kept VM's shell) at their computed keys, then delete them and every
// record the run created.
use abi::repo::delete_record;
use abi::{AtUri, Call};
use serde_json::{Value, json};

use crate::calls::read;
use crate::contract::{Contracting, Phase, finish};
use crate::guest::{STREAM_MAX, Stream};
use crate::ids::CallId;
use crate::input::tags;

pub fn cleanup(c: &mut Contracting) {
    let s = &mut c.state;
    if *c.args.arg("cleanup") == false || s.created.is_empty() {
        return finish(c);
    }
    s.phase = Phase::Cleanup;
    let Some(receipt) = s.receipt.as_ref().map(|r| r.uri.clone()) else { return delete(c) };
    // A kept VM's release (resume) has no tags of its own: the default ones.
    let tags = if s.tags.is_empty() { tags(&Value::Null).unwrap_or_default() } else { s.tags.clone() };
    s.signals = Stream::own(&tags);
    if s.signals.is_empty() {
        return delete(c);
    }
    let reads: Vec<_> = s.signals.iter().enumerate().map(|(i, stream)| (CallId::Page(i), signal_read(c.args.me(), stream, &receipt))).collect();
    c.out.fan_out(&mut s.deletes, reads);
}

fn signal_read(me: &str, stream: &Stream, receipt: &str) -> Call {
    read(&stream.signal(me, receipt).0)
}

// One read of a signal stream: a found payload and its event are the run's to delete and the next
// index is read; a missing one ends that stream.
pub fn signals(c: &mut Contracting, i: usize, result: Result<Value, String>) {
    let s = &mut c.state;
    let receipt = s.receipt.as_ref().map(|r| r.uri.clone()).unwrap_or_default();
    let found = result.as_ref().is_ok_and(|o| o["value"].is_object());
    if let (Some(stream), true) = (s.signals.get_mut(i), found) {
        let (payload, event) = stream.signal(c.args.me(), &receipt);
        for uri in [payload.to_string(), event.to_string()] {
            if !s.created.contains(&uri) {
                s.created.push(uri);
            }
        }
        stream.next += 1;
        if stream.next < STREAM_MAX * 4 {
            let call = signal_read(c.args.me(), stream, &receipt);
            c.out.fan_out(&mut s.deletes, [(CallId::Page(i), call)]);
        }
    }
    if s.deletes.land(&CallId::Page(i), result).is_some() {
        delete(c);
    }
}

fn delete(c: &mut Contracting) {
    let s = &mut c.state;
    let mut deletes = Vec::new();
    for (k, uri) in s.created.iter().enumerate().rev() {
        match uri.parse::<AtUri>() {
            Ok(uri) => deletes.push((CallId::Delete(k), delete_record(&uri))),
            Err(_) => s.errors.push(format!("cannot delete {}: not an at:// record URI", json!(uri))),
        }
    }
    if deletes.is_empty() {
        return finish(c);
    }
    c.out.fan_out(&mut s.deletes, deletes);
}

pub fn deleted(c: &mut Contracting, k: usize, result: Result<Value, String>) {
    let s = &mut c.state;
    match &result {
        Ok(_) => s.deleted.extend(s.created.get(k).cloned()),
        // A record this host's managed_records ledger does not hold is refused: noted, not fatal.
        Err(e) => s.errors.push(format!("delete {}: {e}", s.created.get(k).map(String::as_str).unwrap_or_default())),
    }
    if s.deletes.land(&CallId::Delete(k), result).is_some() {
        finish(c);
    }
}