diff --git a/crates/kernel/src/builtins/bf_server.rs b/crates/kernel/src/builtins/bf_server.rs index 80251076..550df7bf 100644 --- a/crates/kernel/src/builtins/bf_server.rs +++ b/crates/kernel/src/builtins/bf_server.rs @@ -18,7 +18,7 @@ use std::time::{Duration, SystemTime}; use chrono::{DateTime, Local, TimeZone}; use chrono_tz::{OffsetName, Tz}; use iana_time_zone::get_timezone; -use tracing::{debug, error, info, warn}; +use tracing::{error, info, warn}; use moor_compiler::compile; use moor_compiler::{offset_for_builtin, ArgCount, ArgType, Builtin, BUILTINS}; @@ -438,7 +438,6 @@ fn bf_queued_tasks(bf_args: &mut BfCallState<'_>) -> Result { } // Ask the scheduler (through its mailbox) to describe all the queued tasks. - debug!("sending DescribeOtherTasks to scheduler"); let tasks = bf_args.task_scheduler_client.request_queued_tasks(); // return in form: @@ -469,6 +468,58 @@ fn bf_queued_tasks(bf_args: &mut BfCallState<'_>) -> Result { } bf_declare!(queued_tasks, bf_queued_tasks); +/// Function: list queue_info ([obj player]) +/// If player is omitted, returns a list of object numbers naming all players that currently have active task +/// queues inside the server. If player is provided, returns the number of background tasks currently queued for that user. +/// It is guaranteed that queue_info(X) will return zero for any X not in the result of queue_info(). +fn bf_queue_info(bf_args: &mut BfCallState<'_>) -> Result { + if bf_args.args.len() > 1 { + return Err(BfErr::Code(E_ARGS)); + } + + let player = if bf_args.args.is_empty() { + None + } else { + let Variant::Obj(player) = bf_args.args[0].variant() else { + return Err(BfErr::Code(E_TYPE)); + }; + Some(player) + }; + + let tasks = bf_args.task_scheduler_client.request_queued_tasks(); + // Two modes: if player is None, we return a list of all players with queued tasks, but we + // expect wiz perms. + // If player is set, we return the number of tasks queued for that player. + match player { + None => { + // Check wiz perms + bf_args + .task_perms() + .map_err(world_state_bf_err)? + .check_wizard() + .map_err(world_state_bf_err)?; + + // Now we can get the list of players with queued tasks. + let players = tasks + .iter() + .map(|task| task.permissions.clone()) + .collect::>(); + + Ok(Ret(v_list_iter(players.iter().map(|p| v_obj(p.clone()))))) + } + Some(p) => { + // Player must be either a wizard, or the player themselves. + let perms = bf_args.task_perms().map_err(world_state_bf_err)?; + if !perms.check_is_wizard().map_err(world_state_bf_err)? && !p.eq(&perms.who) { + return Err(BfErr::Code(E_PERM)); + } + let queued_tasks = tasks.iter().filter(|t| &t.permissions == p).count(); + Ok(Ret(v_int(queued_tasks as i64))) + } + } +} +bf_declare!(queue_info, bf_queue_info); + fn bf_kill_task(bf_args: &mut BfCallState<'_>) -> Result { // Syntax: kill_task() => none // @@ -1039,6 +1090,7 @@ pub(crate) fn register_bf_server(builtins: &mut [Box]) { builtins[offset_for_builtin("shutdown")] = Box::new(BfShutdown {}); builtins[offset_for_builtin("suspend")] = Box::new(BfSuspend {}); builtins[offset_for_builtin("queued_tasks")] = Box::new(BfQueuedTasks {}); + builtins[offset_for_builtin("queue_info")] = Box::new(BfQueueInfo {}); builtins[offset_for_builtin("kill_task")] = Box::new(BfKillTask {}); builtins[offset_for_builtin("resume")] = Box::new(BfResume {}); builtins[offset_for_builtin("ticks_left")] = Box::new(BfTicksLeft {}); diff --git a/doc/builtin_functions_status.md b/doc/builtin_functions_status.md index 438b63f8..8ef4f420 100644 --- a/doc/builtin_functions_status.md +++ b/doc/builtin_functions_status.md @@ -9,7 +9,7 @@ included in the notes column. ### Lists | Name | Complete | Notes | -|--------------|----------|-------| +| ------------ | -------- | ----- | | `length` | ✓ | | | `setadd` | ✓ | | | `setremove` | ✓ | | @@ -26,7 +26,7 @@ included in the notes column. ### Strings | Name | Complete | Notes | -|-------------|----------|--------------------------------------------------------------------------------| +| ----------- | -------- | ------------------------------------------------------------------------------ | | `tostr` | ✓ | | | `toliteral` | ✓ | | | `crypt` | ✓ | Pretty damned insecure, only here to support existing core password functions. | @@ -38,7 +38,7 @@ included in the notes column. ### Numbers | Name | Complete | Notes | -|------------|----------|-------| +| ---------- | -------- | ----- | | `toint` | ✓ | | | `tonum` | ✓ | | | `tofloat` | ✓ | | @@ -69,7 +69,7 @@ included in the notes column. ### Objects | Name | Complete | Notes | -|-------------------|----------|------------------------------------| +| ----------------- | -------- | ---------------------------------- | | `toobj` | ✓ | | | `typeof` | ✓ | | | `create` | ✓ | Quota support not implemented yet. | @@ -87,7 +87,7 @@ included in the notes column. ### Properties | Name | Complete | Notes | -|---------------------|----------|-------| +| ------------------- | -------- | ----- | | `properties` | ✓ | | | `property_info` | ✓ | | | `set_property_info` | ✓ | | @@ -99,7 +99,7 @@ included in the notes column. ### Verbs | Name | Complete | Notes | -|-----------------|----------|---------------------------------------| +| --------------- | -------- | ------------------------------------- | | `verbs` | ✓ | | | `verb_info` | ✓ | | | `set_verb_info` | ✓ | | @@ -115,7 +115,7 @@ included in the notes column. ### Values / encoding | Name | Complete | Notes | -|-----------------|----------|------------------------------------------------------------------------------------| +| --------------- | -------- | ---------------------------------------------------------------------------------- | | `value_bytes` | ✓ | | | `value_hash` | | | | `string_hash` | ✓ | | @@ -127,7 +127,7 @@ included in the notes column. ### Server | Name | Complete | Notes | -|-----------------------|----------|--------------------------------------------------------------------------| +| --------------------- | -------- | ------------------------------------------------------------------------ | | `server_version` | ✓ | Hardcoded value, should derive from bin crate | | `renumber` | | | | `reset_max_object` | | | @@ -149,19 +149,19 @@ included in the notes column. ### Tasks | Name | Complete | Notes | -|----------------|----------|-------| +| -------------- | -------- | ----- | | `task_id` | ✓ | | | `queued_tasks` | ✓ | | | `kill_task` | ✓ | | | `resume` | ✓ | | -| `queue_info` | | | +| `queue_info` | ✓ | | | `force_input` | | | | `flush_input` | | | ### Execution | Name | Complete | Notes | -|------------------|----------|--------------| +| ---------------- | -------- | ------------ | | `call_function` | ✓ | | | `raise` | ✓ | | | `suspend` | ✓ | | @@ -176,7 +176,7 @@ included in the notes column. ### Network connections | Name | Complete | Notes | -|---------------------------|----------|------------------------------------------------------------------------------------------------------| +| ------------------------- | -------- | ---------------------------------------------------------------------------------------------------- | | `set_connection_option` | | | | `connection_option` | | | | `connection_options` | | | @@ -194,6 +194,6 @@ Functions not part of the original LambdaMOO, but added in moor ### XML / HTML content management | Name | Description | Notes | -|-------------|------------------------------------------------------------------|-------------------------------------------------------| +| ----------- | ---------------------------------------------------------------- | ----------------------------------------------------- | | `xml_parse` | Parse a string c ntaining XML into a tree of flyweight objects | Available only if the flyweights feature is turned on | | `to_xml` | Convert a tree of flyweight objects into a string containing XML | Available only if the flyweights feature is turned on |