Skip to content

Commit

Permalink
Allow BfNotify to send non-string values to host/client
Browse files Browse the repository at this point in the history
  * When in non-strict mode (default), `notify` can now send any MOO
    value to the client.
  * The "telnet" host unwraps strings to the usual text output, but
    turns everything else into its literal value form.
  * The web host turns everything into JSON.
  • Loading branch information
rdaum committed Aug 4, 2024
1 parent a588162 commit a1f7ce6
Show file tree
Hide file tree
Showing 8 changed files with 41 additions and 18 deletions.
2 changes: 1 addition & 1 deletion crates/console-host/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ fn console_loop(
printer
.print(
(match msg.event() {
moor_values::tasks::Event::TextNotify(s) => s,
moor_values::tasks::Event::Notify(s) => s,
})
.to_string(),
)
Expand Down
11 changes: 7 additions & 4 deletions crates/kernel/src/builtins/bf_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use crate::builtins::BfRet::{Ret, VmInstr};
use crate::builtins::{world_state_bf_err, BfCallState, BfErr, BfRet, BuiltinFunction};
use crate::vm::ExecutionResult;
use moor_values::tasks::TaskId;
use moor_values::var::VarType::TYPE_STR;

fn bf_noop(bf_args: &mut BfCallState<'_>) -> Result<BfRet, BfErr> {
error!(
Expand All @@ -57,10 +58,12 @@ fn bf_notify(bf_args: &mut BfCallState<'_>) -> Result<BfRet, BfErr> {
let Variant::Obj(player) = player else {
return Err(BfErr::Code(E_TYPE));
};
let msg = bf_args.args[1].variant();
let Variant::Str(msg) = msg else {

// If in "strict" mode `notify` can only send text.
// Otherwise, it can send any value, and it's up to the host/client to interpret it.
if bf_args.config.strict_mode && bf_args.args[1].type_id() != TYPE_STR {
return Err(BfErr::Code(E_TYPE));
};
}

// If player is not the calling task perms, or a caller is not a wizard, raise E_PERM.
bf_args
Expand All @@ -69,7 +72,7 @@ fn bf_notify(bf_args: &mut BfCallState<'_>) -> Result<BfRet, BfErr> {
.check_obj_owner_perms(*player)
.map_err(world_state_bf_err)?;

let event = NarrativeEvent::notify_text(bf_args.exec_state.caller(), msg.to_string());
let event = NarrativeEvent::notify(bf_args.exec_state.caller(), bf_args.args[1].clone());
bf_args.task_scheduler_client.notify(*player, event);

// MOO docs say this should return none, but in reality it returns 1?
Expand Down
3 changes: 3 additions & 0 deletions crates/kernel/src/builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use crate::builtins::bf_server::{register_bf_server, BfNoop};
use crate::builtins::bf_strings::register_bf_strings;
use crate::builtins::bf_values::register_bf_values;
use crate::builtins::bf_verbs::register_bf_verbs;
use crate::config::Config;
use crate::tasks::sessions::Session;
use crate::tasks::task_scheduler_client::TaskSchedulerClient;
use crate::vm::activation::{BfFrame, Frame};
Expand Down Expand Up @@ -96,6 +97,8 @@ pub struct BfCallState<'a> {
pub(crate) session: Arc<dyn Session>,
/// For sending messages up to the scheduler
pub(crate) task_scheduler_client: TaskSchedulerClient,
/// Config
pub(crate) config: Arc<Config>,
}

impl BfCallState<'_> {
Expand Down
2 changes: 1 addition & 1 deletion crates/kernel/src/tasks/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -857,7 +857,7 @@ mod tests {
};
assert_eq!(player, SYSTEM_OBJECT);
assert_eq!(event.author(), SYSTEM_OBJECT);
assert_eq!(event.event, Event::TextNotify("12345".to_string()));
assert_eq!(event.event, Event::Notify(v_str("12345")));

// Also scheduler should have received a TaskSuccess message.
let (task_id, msg) = control_receiver.recv().unwrap();
Expand Down
2 changes: 2 additions & 0 deletions crates/kernel/src/vm/vm_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ impl VMExecState {
// TODO: avoid copy here by using List inside BfCallState
args: args.iter().collect(),
task_scheduler_client: exec_args.task_scheduler_client.clone(),
config: exec_args.config.clone(),
};

let call_results = match bf.call(&mut bf_args) {
Expand Down Expand Up @@ -308,6 +309,7 @@ impl VMExecState {
// TODO: avoid copy here by using List inside BfCallState
args: args.iter().collect(),
task_scheduler_client: exec_args.task_scheduler_client.clone(),
config: exec_args.config.clone(),
};

match bf.call(&mut bf_args) {
Expand Down
24 changes: 19 additions & 5 deletions crates/telnet-host/src/telnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use uuid::Uuid;

use moor_values::tasks::{AbortLimitReason, CommandError, Event, SchedulerError, VerbProgramError};
use moor_values::util::parse_into_words;
use moor_values::var::Objid;
use moor_values::var::{Objid, Variant};
use rpc_async_client::pubsub_client::{broadcast_recv, events_recv};
use rpc_async_client::rpc_client::RpcSendClient;
use rpc_common::RpcRequest::ConnectionEstablish;
Expand Down Expand Up @@ -142,8 +142,15 @@ impl TelnetConnection {
}
ConnectionEvent::Narrative(_author, event) => {
let msg = event.event();
let Event::TextNotify(msg_text) = msg;
self.write.send(msg_text).await.with_context(|| "Unable to send message to client")?;
let Event::Notify(msg) = msg;

// Strings output as text lines to the client, otherwise send the
// literal form (for e.g. lists, objrefs, etc)
if let Variant::Str(msg_text) = msg.variant() {
self.write.send(msg_text.to_string()).await.with_context(|| "Unable to send message to client")?;
} else {
self.write.send(msg.to_literal()).await.with_context(|| "Unable to send message to client")?;
}
}
ConnectionEvent::RequestInput(_request_id) => {
bail!("RequestInput before login");
Expand Down Expand Up @@ -307,8 +314,15 @@ impl TelnetConnection {
}
ConnectionEvent::Narrative(_author, event) => {
let msg = event.event();
let Event::TextNotify(msg_text) = msg;
self.write.send(msg_text).await.with_context(|| "Unable to send message to client")?;
let Event::Notify(msg) = msg;

// Strings output as text lines to the client, otherwise send the
// literal form (for e.g. lists, objrefs, etc)
if let Variant::Str(msg_text) = msg.variant() {
self.write.send(msg_text.to_string()).await.with_context(|| "Unable to send message to client")?;
} else {
self.write.send(msg.to_literal()).await.with_context(|| "Unable to send message to client")?;
}
}
ConnectionEvent::RequestInput(request_id) => {
// Server is requesting that the next line of input get sent through as a response to this request.
Expand Down
8 changes: 4 additions & 4 deletions crates/values/src/tasks/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// this program. If not, see <https://www.gnu.org/licenses/>.
//

use crate::var::Objid;
use crate::var::{Objid, Var};
use bincode::{Decode, Encode};
use std::time::SystemTime;

Expand All @@ -32,19 +32,19 @@ pub struct NarrativeEvent {
#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)]
pub enum Event {
/// The typical "something happened" descriptive event.
TextNotify(String),
Notify(Var),
// TODO: Other Event types on Session stream
// other events that might happen here would be things like (local) "object moved" or "object
// created."
}

impl NarrativeEvent {
#[must_use]
pub fn notify_text(author: Objid, event: String) -> Self {
pub fn notify(author: Objid, value: Var) -> Self {
Self {
timestamp: SystemTime::now(),
author,
event: Event::TextNotify(event),
event: Event::Notify(value),
}
}

Expand Down
7 changes: 4 additions & 3 deletions crates/web-host/src/host/ws_connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// this program. If not, see <https://www.gnu.org/licenses/>.
//

use crate::host::serialize_var;
use crate::host::{serialize_var, var_as_json};
use axum::extract::ws::{Message, WebSocket};
use futures_util::stream::SplitSink;
use futures_util::{SinkExt, StreamExt};
Expand All @@ -26,6 +26,7 @@ use rpc_common::ConnectionEvent;
use rpc_common::{
AuthToken, ClientToken, ConnectType, RpcRequest, RpcRequestError, RpcResponse, RpcResult,
};
use serde_json::Value;
use std::net::SocketAddr;
use std::time::SystemTime;
use tmq::subscribe::Subscribe;
Expand All @@ -51,7 +52,7 @@ pub struct NarrativeOutput {
#[serde(skip_serializing_if = "Option::is_none")]
system_message: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
message: Option<String>,
message: Option<Value>,
server_time: SystemTime,
}

Expand Down Expand Up @@ -124,7 +125,7 @@ impl WebSocketConnection {
origin_player: author.0,
system_message: None,
message: Some(match msg {
Event::TextNotify(msg) => msg,
Event::Notify(msg) => var_as_json(&msg),
}),
server_time: event.timestamp(),
}).await;
Expand Down

0 comments on commit a1f7ce6

Please sign in to comment.