// cell config - Manage system and actor configurations var toml = use('toml') var pkg = use('package') function print_help() { log.console("Usage: cell config [options]") log.console("") log.console("Commands:") log.console(" get Get a configuration value") log.console(" set Set a configuration value") log.console(" list List all configurations") log.console(" actor get Get actor-specific config") log.console(" actor set Set actor-specific config") log.console(" actor list List actor configurations") log.console("") log.console("Examples:") log.console(" cell config get system.ar_timer") log.console(" cell config set system.net_service 0.2") log.console(" cell config actor prosperon/_sdl_video set resolution 1920x1080") log.console(" cell config actor extramath/spline set precision high") log.console("") log.console("System keys:") log.console(" system.ar_timer - Seconds before idle actor reclamation") log.console(" system.actor_memory - MB of memory an actor can use (0=unbounded)") log.console(" system.net_service - Seconds per network service pull") log.console(" system.reply_timeout - Seconds to hold callback for replies (0=unbounded)") log.console(" system.actor_max - Max number of simultaneous actors") log.console(" system.stack_max - MB of memory each actor's stack can grow to") } // Parse a dot-notation key into path segments function parse_key(key) { return array(key, '.') } // Get a value from nested object using path function get_nested(obj, path) { var current = obj arrfor(path, function(segment) { if (is_null(current) || !is_object(current)) return null current = current[segment] }) return current } // Set a value in nested object using path function set_nested(obj, path, value) { var current = obj var i = 0 var segment = null for (i = 0; i < length(path) - 1; i++) { segment = path[i] if (is_null(current[segment]) || !is_object(current[segment])) { current[segment] = {} } current = current[segment] } current[path[length(path) - 1]] = value } // Parse value string into appropriate type function parse_value(str) { var num_str = null var n = null // Boolean if (str == 'true') return true if (str == 'false') return false // Number num_str = replace(str, /_/g, '') n = number(num_str) if (n != null) return n // String return str } // Format value for display function format_value(val) { if (is_text(val)) return '"' + val + '"' return text(val) } // Print configuration tree recursively function print_config(obj, pfx) { var p = pfx || '' arrfor(array(obj), function(key) { var val = obj[key] var full_key = p ? p + '.' + key : key if (is_object(val)) print_config(val, full_key) else if (!is_null(val)) log.console(full_key + ' = ' + format_value(val)) }) } // Main command handling if (length(args) == 0) { print_help() $stop() } var config = pkg.load_config() if (!config) { log.error("Failed to load cell.toml") $stop() } var command = args[0] var key = null var path = null var value = null var value_str = null var valid_system_keys = null var actor_name = null var actor_cmd = null if (command == 'help' || command == '-h' || command == '--help') { print_help() } else if (command == 'list') { log.console("# Cell Configuration") log.console("") print_config(config) } else if (command == 'get') { if (length(args) < 2) { log.error("Usage: cell config get ") $stop() } key = args[1] path = parse_key(key) value = get_nested(config, path) if (value == null) { log.error("Key not found: " + key) } else if (is_object(value)) { print_config(value, key) } else { log.console(key + ' = ' + format_value(value)) } } else if (command == 'set') { if (length(args) < 3) { log.error("Usage: cell config set ") $stop() } key = args[1] value_str = args[2] path = parse_key(key) value = parse_value(value_str) if (path[0] == 'system') { valid_system_keys = [ 'ar_timer', 'actor_memory', 'net_service', 'reply_timeout', 'actor_max', 'stack_max' ] if (find(valid_system_keys, path[1]) == null) { log.error("Invalid system key. Valid keys: " + text(valid_system_keys, ', ')) $stop() } } set_nested(config, path, value) pkg.save_config(config) log.console("Set " + key + " = " + format_value(value)) } else if (command == 'actor') { if (length(args) < 3) { log.error("Usage: cell config actor [options]") $stop() } actor_name = args[1] actor_cmd = args[2] config.actors = config.actors || {} config.actors[actor_name] = config.actors[actor_name] || {} if (actor_cmd == 'list') { if (length(array(config.actors[actor_name])) == 0) { log.console("No configuration for actor: " + actor_name) } else { log.console("# Configuration for actor: " + actor_name) log.console("") print_config(config.actors[actor_name], 'actors.' + actor_name) } } else if (actor_cmd == 'get') { if (length(args) < 4) { log.error("Usage: cell config actor get ") $stop() } key = args[3] path = parse_key(key) value = get_nested(config.actors[actor_name], path) if (value == null) { log.error("Key not found for actor " + actor_name + ": " + key) } else { log.console('actors.' + actor_name + '.' + key + ' = ' + format_value(value)) } } else if (actor_cmd == 'set') { if (length(args) < 5) { log.error("Usage: cell config actor set ") $stop() } key = args[3] value_str = args[4] path = parse_key(key) value = parse_value(value_str) set_nested(config.actors[actor_name], path, value) pkg.save_config(config) log.console("Set actors." + actor_name + "." + key + " = " + format_value(value)) } else { log.error("Unknown actor command: " + actor_cmd) log.console("Valid commands: list, get, set") } } else { log.error("Unknown command: " + command) print_help() } $stop()