interpreter: new read_actions_component

Rejects stanza without an @to, and automatically adds @from.

Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
Maxime “pep” Buquet 2023-07-27 23:52:58 +02:00
parent 365f5d60a2
commit d4a8719e09
2 changed files with 70 additions and 3 deletions

View file

@ -15,8 +15,8 @@
use crate::element::{ScanElement, DEFAULT_NS, SCANSION_NS}; use crate::element::{ScanElement, DEFAULT_NS, SCANSION_NS};
use crate::parsers::{parse_spec, Token}; use crate::parsers::{parse_spec, Token};
use crate::types::{Action, Context, Entity, Spec}; use crate::types::{Action, Client, Context, Entity, Spec};
use jid::Jid; use jid::{BareJid, Jid};
use minidom::{Element, Error as MinidomError}; use minidom::{Element, Error as MinidomError};
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
use std::collections::BTreeMap; use std::collections::BTreeMap;
@ -115,6 +115,73 @@ pub fn read_actions(spec: Spec, context: &Context) -> Result<InOutStanza, Minido
Ok(inout) Ok(inout)
} }
/// Reads Actions from Spec and converts that to InOutStanza. Also ensures @to and @from attributes
/// are set. Rejects stanza without an @to, and automatically adds @from.
pub fn read_actions_component(spec: Spec, context: &Context) -> Result<InOutStanza, MinidomError> {
let mut inout = InOutStanza::new();
for action in spec.actions {
match action {
Action::Receive(name, s) => {
let _jid = context
.get(&name)
.expect(format!("Name '{}' not found in clients", name).as_str());
let prefixes: BTreeMap<Option<String>, String> = {
let mut tmp = BTreeMap::new();
tmp.insert(None, String::from(DEFAULT_NS));
tmp.insert(Some(String::from("scansion")), String::from(SCANSION_NS));
tmp
};
let elem: Element =
Element::from_reader_with_prefixes(s.as_ref(), prefixes).unwrap();
inout.receives(ScanElement::new(elem).apply_context(&context));
}
Action::Send(name, s) => {
let client = context
.get(&name)
.expect(format!("Name '{}' not found in clients", name).as_str());
let jid: BareJid = match client {
Entity::Client(Client {
jid: Jid::Full(full),
..
}) => BareJid::from(full.clone()),
Entity::Client(Client {
jid: Jid::Bare(bare),
..
}) => bare.clone(),
};
let prefixes: BTreeMap<Option<String>, String> = {
let mut tmp = BTreeMap::new();
tmp.insert(None, String::from(DEFAULT_NS));
tmp.insert(Some(String::from("scansion")), String::from(SCANSION_NS));
tmp
};
let mut elem: Element =
Element::from_reader_with_prefixes(s.as_ref(), prefixes).unwrap();
// Ensure stanza have to/from parameters. We may be able to infer where the stanza
// comes from but we need them to be addressed to the component explicitely.
assert_ne!(
elem.attr("to"),
None,
"Stanza sent by '{}' should possess a 'to' parameter",
name,
);
if elem.attr("from").is_none() {
elem.set_attr("from", Jid::Bare(jid));
}
inout.sends(ScanElement::new(elem).apply_context(&context));
}
_ => (),
}
}
Ok(inout)
}
pub fn read_spec<'a, 'b>(buf: &str) -> Result<Spec, Token> { pub fn read_spec<'a, 'b>(buf: &str) -> Result<Spec, Token> {
let mut spec = parse_spec(buf)?; let mut spec = parse_spec(buf)?;
spec.context = bind_context(spec.context.clone()); spec.context = bind_context(spec.context.clone());

View file

@ -12,6 +12,6 @@ pub mod parsers;
pub mod types; pub mod types;
pub use element::ScanElement; pub use element::ScanElement;
pub use interpreter::{read_actions, read_spec}; pub use interpreter::{read_actions, read_actions_component, read_spec};
pub use parsers::parse_spec; pub use parsers::parse_spec;
pub use types::{Action, Client, Context, Entity, Metadata, Name, Spec}; pub use types::{Action, Client, Context, Entity, Metadata, Name, Spec};