Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow "rich" host/client output #365

Merged
merged 4 commits into from
Aug 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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: 10 additions & 1 deletion crates/daemon/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ struct Args {
#[arg(
long,
value_name = "textdump-encoding",
help = "Encoding to use for reading textdump files. utf8 or iso8859-1. \
help = "Encoding to use for reading and writing textdump files. utf8 or iso8859-1. \
LambdaMOO textdumps that contain 8-bit strings are written using iso8859-1, so for full compatibility, \
choose iso8859-1.
If you know your textdump contains no such strings, or if your textdump is from moor choose utf8,
Expand Down Expand Up @@ -190,6 +190,13 @@ struct Args {

#[arg(long, help = "Enable debug logging", default_value = "false")]
debug: bool,

#[arg(
long,
help = "Enable strict mode, which constraints behaviours to original LambdaMOO",
default_value = "false"
)]
strict_mode: bool,
}

fn main() -> Result<(), Report> {
Expand Down Expand Up @@ -294,6 +301,8 @@ fn main() -> Result<(), Report> {

let config = Config {
textdump_output: args.textdump_out,
textdump_encoding: args.textdump_encoding,
strict_mode: args.strict_mode,
};

let tasks_db: Box<dyn TasksDb> = match args.db_flavour {
Expand Down
4 changes: 4 additions & 0 deletions crates/kernel/benches/vm_benches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use criterion::{criterion_group, criterion_main, Criterion};
use moor_compiler::compile;
use moor_db_wiredtiger::WiredTigerDB;
use moor_kernel::builtins::BuiltinRegistry;
use moor_kernel::config::Config;
use moor_kernel::tasks::sessions::{NoopClientSession, Session};
use moor_kernel::tasks::task_scheduler_client::TaskSchedulerClient;
use moor_kernel::tasks::vm_host::{VMHostResponse, VmHost};
Expand Down Expand Up @@ -109,6 +110,8 @@ fn execute(
vm_host.reset_ticks();
vm_host.reset_time();

let config = Arc::new(Config::default());

// Call repeatedly into exec until we ge either an error or Complete.
loop {
match vm_host.exec_interpreter(
Expand All @@ -117,6 +120,7 @@ fn execute(
task_scheduler_client.clone(),
session.clone(),
Arc::new(BuiltinRegistry::new()),
config.clone(),
) {
VMHostResponse::ContinueOk => {
continue;
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
9 changes: 8 additions & 1 deletion crates/kernel/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,16 @@
//! Config is created by the host daemon, and passed through the scheduler, whereupon it is
//! available to all components. Used to hold things typically configured by CLI flags, etc.

use crate::textdump::EncodingMode;
use std::path::PathBuf;

#[derive(Debug, Default)]
#[derive(Clone, Debug, Default)]
pub struct Config {
/// Whether to run in a strict mode which ties the server to the original LambdaMOO behaviour,
/// or to allow for more modern features.
pub strict_mode: bool,
/// Where to write periodic textdumps of the database.
pub textdump_output: Option<PathBuf>,
/// What encoding to use for textdumps (ISO-8859-1 or UTF-8).
pub textdump_encoding: EncodingMode,
}
4 changes: 4 additions & 0 deletions crates/kernel/src/tasks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ pub mod vm_test_utils {
use moor_values::SYSTEM_OBJECT;

use crate::builtins::BuiltinRegistry;
use crate::config::Config;
use crate::tasks::sessions::Session;
use crate::tasks::vm_host::{VMHostResponse, VmHost};
use crate::tasks::VerbCall;
Expand All @@ -152,6 +153,8 @@ pub mod vm_test_utils {

fun(world_state, &mut vm_host);

let config = Arc::new(Config::default());

// Call repeatedly into exec until we ge either an error or Complete.
loop {
match vm_host.exec_interpreter(
Expand All @@ -160,6 +163,7 @@ pub mod vm_test_utils {
task_scheduler_client.clone(),
session.clone(),
builtins.clone(),
config.clone(),
) {
VMHostResponse::ContinueOk => {
continue;
Expand Down
27 changes: 23 additions & 4 deletions crates/kernel/src/tasks/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ use crate::tasks::{
ServerOptions, TaskHandle, TaskStart, DEFAULT_BG_SECONDS, DEFAULT_BG_TICKS, DEFAULT_FG_SECONDS,
DEFAULT_FG_TICKS, DEFAULT_MAX_STACK_DEPTH,
};
use crate::textdump::{make_textdump, EncodingMode, TextdumpWriter};
use crate::textdump::{make_textdump, TextdumpWriter};
use crate::vm::Fork;
use moor_values::tasks::SchedulerError::{
CommandExecutionError, InputRequestNotFound, TaskAbortedCancelled, TaskAbortedError,
Expand Down Expand Up @@ -85,7 +85,7 @@ pub struct Scheduler {
scheduler_sender: Sender<SchedulerClientMsg>,
scheduler_receiver: Receiver<SchedulerClientMsg>,

config: Config,
config: Arc<Config>,

running: bool,
database: Box<dyn Database>,
Expand Down Expand Up @@ -169,7 +169,7 @@ impl Scheduler {
database,
next_task_id: Default::default(),
task_q,
config,
config: Arc::new(config),
task_control_sender,
task_control_receiver,
scheduler_sender,
Expand Down Expand Up @@ -202,6 +202,7 @@ impl Scheduler {
&self.task_control_sender,
self.database.as_ref(),
self.builtin_registry.clone(),
self.config.clone(),
) {
error!(?task_id, ?e, "Error resuming task");
}
Expand Down Expand Up @@ -370,6 +371,7 @@ impl Scheduler {
&self.task_control_sender,
self.database.as_ref(),
self.builtin_registry.clone(),
self.config.clone(),
);
reply
.send(result)
Expand Down Expand Up @@ -405,6 +407,7 @@ impl Scheduler {
&self.task_control_sender,
self.database.as_ref(),
self.builtin_registry.clone(),
self.config.clone(),
);
reply
.send(result)
Expand Down Expand Up @@ -441,6 +444,7 @@ impl Scheduler {
&self.task_control_sender,
self.database.as_ref(),
self.builtin_registry.clone(),
self.config.clone(),
);
reply.send(response).expect("Could not send input reply");
}
Expand Down Expand Up @@ -472,6 +476,7 @@ impl Scheduler {
&self.task_control_sender,
self.database.as_ref(),
self.builtin_registry.clone(),
self.config.clone(),
);
reply
.send(result)
Expand All @@ -498,6 +503,7 @@ impl Scheduler {
&self.task_control_sender,
self.database.as_ref(),
self.builtin_registry.clone(),
self.config.clone(),
);
reply
.send(result)
Expand Down Expand Up @@ -608,6 +614,7 @@ impl Scheduler {
self.database.as_ref(),
&self.server_options,
self.builtin_registry.clone(),
self.config.clone(),
);
}
TaskControlMsg::TaskVerbNotFound(this, verb) => {
Expand Down Expand Up @@ -802,6 +809,7 @@ impl Scheduler {
&self.task_control_sender,
self.database.as_ref(),
self.builtin_registry.clone(),
self.config.clone(),
);
if let Err(e) = result_sender.send(rr) {
error!(?e, "Could not send resume task result to requester");
Expand Down Expand Up @@ -844,6 +852,8 @@ impl Scheduler {
return Err(SchedulerError::CouldNotStartTask);
};

let encoding_mode = self.config.textdump_encoding;

let loader_client = {
match self.database.loader_client() {
Ok(tx) => tx,
Expand All @@ -870,7 +880,7 @@ impl Scheduler {
);

debug!(?textdump_path, "Writing textdump..");
let mut writer = TextdumpWriter::new(&mut output, EncodingMode::UTF8);
let mut writer = TextdumpWriter::new(&mut output, encoding_mode);
if let Err(e) = writer.write_textdump(&textdump) {
error!(?e, "Could not write textdump");
return;
Expand Down Expand Up @@ -917,6 +927,7 @@ impl Scheduler {
&self.task_control_sender,
self.database.as_ref(),
self.builtin_registry.clone(),
self.config.clone(),
) {
Ok(th) => th,
Err(e) => {
Expand Down Expand Up @@ -979,6 +990,7 @@ impl TaskQ {
control_sender: &Sender<(TaskId, TaskControlMsg)>,
database: &dyn Database,
builtin_registry: Arc<BuiltinRegistry>,
config: Arc<Config>,
) -> Result<TaskHandle, SchedulerError> {
let (sender, receiver) = oneshot::channel();

Expand Down Expand Up @@ -1069,6 +1081,7 @@ impl TaskQ {
session,
world_state,
builtin_registry,
config,
);
trace!(?task_id, "Completed task");
})
Expand All @@ -1095,6 +1108,7 @@ impl TaskQ {
control_sender: &Sender<(TaskId, TaskControlMsg)>,
database: &dyn Database,
builtin_registry: Arc<BuiltinRegistry>,
config: Arc<Config>,
) -> Result<(), SchedulerError> {
// Take a task out of a suspended state and start running it again.
// Means:
Expand Down Expand Up @@ -1135,6 +1149,7 @@ impl TaskQ {
session,
world_state,
builtin_registry,
config,
);
trace!(?task_id, "Completed task");
})
Expand Down Expand Up @@ -1172,6 +1187,7 @@ impl TaskQ {
database: &dyn Database,
server_options: &ServerOptions,
builtin_registry: Arc<BuiltinRegistry>,
config: Arc<Config>,
) {
// Make sure the old thread is dead.
task.kill_switch.store(true, Ordering::SeqCst);
Expand All @@ -1198,6 +1214,7 @@ impl TaskQ {
control_sender,
database,
builtin_registry,
config,
) {
error!(?e, "Could not restart task");
}
Expand Down Expand Up @@ -1267,6 +1284,7 @@ impl TaskQ {
control_sender: &Sender<(TaskId, TaskControlMsg)>,
database: &dyn Database,
builtin_registry: Arc<BuiltinRegistry>,
config: Arc<Config>,
) -> Var {
// Task can't resume itself, it couldn't be queued. Builtin should not have sent this
// request.
Expand Down Expand Up @@ -1303,6 +1321,7 @@ impl TaskQ {
control_sender,
database,
builtin_registry,
config,
)
.is_err()
{
Expand Down
Loading
Loading