/
CDC-1.2b/
CDC-1.2b/src/
parent $utilities
object $scheduler_crag

var $root child_index 0
var $root owners [$scheduler_crag]
var $root owned [$scheduler_crag]
var $root fertile 0
var $root inited 1
var $scheduler_crag tasks <$small_first_heap_class, #[['key, 'run_time], ['data, [#[['tid, 7], ['run_time, 762498497], ['instime, 762498467], ['sender, $], ['caller, $], ['method, 'tell], ['flags, ['system]], ['owner, $], ['args, ["foo"]]], #[['tid, 8], ['run_time, 762498498], ['instime, 762498468], ['sender, $], ['caller, $], ['method, 'tell], ['flags, ['system]], ['owner, $], ['args, ["foo"]]], #[['tid, 9], ['run_time, 762498499], ['instime, 762498469], ['sender, $], ['caller, $], ['method, 'tell], ['flags, ['system]], ['owner, $], ['args, ["foo"]]], #[['tid, 10], ['run_time, 762498500], ['instime, 762498470], ['sender, $], ['caller, $], ['method, 'tell], ['flags, ['system]], ['owner, $], ['args, ["foo"]]], #[['tid, 11], ['run_time, 762498506], ['instime, 762498503], ['sender, $], ['caller, $], ['method, 'tell], ['flags, ['system]], ['owner, $], ['args, ["foo"]]]]]]>
var $scheduler_crag task_index 12
var $root manager $scheduler_crag
var $root writable [$scheduler_crag]
var $root readable ['parameters, 'methods, 'code]
var $root dbref 'scheduler_crag

method _insert_task
    arg tid, extime, instime, sender, caller, method, flags, owner, args;
    
    // inserts a task into the correct order.  Callable only by this.
    if (sender() != this())
        throw(~perm, "Sender is not this");
    tasks = tasks.add(#[['tid, tid], ['run_time, extime + instime], ['instime, instime], ['sender, sender], ['caller, caller], ['method, method], ['flags, flags], ['owner, owner], ['args, args]]);
.

method pulse
    // called by $sys.heartbeat.
    if (caller() != $sys)
        throw(~perm, "Sender is not system");
    while ((tasks.length()) && ((time() > ((tasks.element(1))['run_time])) && (._run_task()))) {
        // do nothing?
    }
.

method _run_task
    var task, code, args, a;
    
    // called by $scheduler only
    if (caller() != this())
        throw(~perm, "Caller is not this");
    task = tasks.element(1);
    catch any {
        // setup the args by hand, becuase we use eval and it expects a string
        args = task['args];
        if (args) {
            for a in [1 .. listlen(args)]
                args = replace(args, a, $data.unparse(args[a]));
            args = $list.to_string(args, ",");
        } else {
            args = "";
        }
        code = ((("." + tostr(task['method])) + "(") + args) + ");";
    
        // run it through eval as the sender():
        (task['caller]).eval([code], task['sender]);
        return ._del_task(1);
    } with handler {
        // bounce the errors to the person, or to the system board if it's 'system
        catch any {
            (task['owner]).tell(["SCHEDULER ERROR: ", @traceback()]);
        } with handler {
            if ((task['owner]) == 'system) {
                $channels.announce('System, traceback()[1]);
                $channels.announce('System, "task: " + ($data.unparse(task)));
            }
        }
        return 0;
    }
.

method queue
    arg [owner];
    var task, atasks, queue, t;
    
    // return tasks queued under owner, or return all if is admin.
    if ((!owner) && ($sys.is_admin(sender())))
        owner = 'all;
    else
        owner = [@owner, sender()][1];
    
    // if (owner == 'all)
    //   atasks = tasks;
    // else
    //   atasks = owners[owner];
    if (owner || (!($sys.is_admin(sender())))) {
        queue = $small_first_heap_class.new([], 'run_time);
        for t in [1 .. queue.length()] {
            if (((tasks.element(t))['owner]) == owner)
                queue.add(tasks.element(t));
        }
    } else {
        queue = tasks;
    }
    return queue;
.

method del_task
    arg tid;
    var task;
    
    if (type(tid) != 'integer)
        throw(~type, "Task Identification must be an integer");
    if (!(tid in tasks))
        throw(~tasknf, ("No task found by the TID of `" + tostr(tid)) + "'");
    if ((task_owner[tid]) != sender())
        throw(~perm, "Sender does not have permissions to kill this task.");
    
    // ok, delete it
    ._del_task(tid in ($list.slice(.tasks(), 'tid)));
.

method tasks
    return tasks.data();
.

method sys_del_task
    arg tid;
    var task;
    
    // sender must be system
    if (!($sys.is_agent(sender())))
        throw(~perm, "Sender does not have system privelages");
    if (type(tid) != 'integer)
        throw(~type, "Task Identification must be an integer");
    if (!(tid in tasks))
        throw(~tasknf, ("No task found by the TID of `" + tostr(tid)) + "'");
    
    // ok, delete it.
    ._del_task(tid in ($list.slice(.tasks(), 'tid)));
.

method _del_task
    arg task;
    
    // assumes that the $scheduler has already checked everything.
    if (sender() != this())
        throw(~perm, "Sender is not this");
    tasks = tasks.del(task);
.

method sys_bump_task
    arg tid;
    var task_index, task;
    
    // bumps a task up to be executed next
    if ((!($sys.is_agent(sender()))) || (!($sys.is_admin(sender()))))
        throw(~perm, "Sender does not have system perms");
    
    // the meat
    task_index = tid in (.tasks());
    if (!task_index)
        throw(~tasknf, "Task not found.");
    if (task_index == 1)
        return;
    task = tasks.element(task_index);
    tasks = tasks.del(task_index);
    task = task.replace('run_time, $list.min(((tasks.element(1))['run_time]) - 1, time()));
    tasks = tasks.add(task);
.

method add_task
    arg time, method, [args];
    var tid, flags, owner, task;
    
    // use `@info $scheduler' for more information.
    // time is seconds from insertion time that it will be run (ie 300 == 5 mins)
    //
    if ((type(time) != 'integer) || ((type(method) != 'symbol) || (type(args) != 'list)))
        throw(~type, "Arguments are not an integer, symbol, and list.");
    if (time < 1)
        throw(~time, "Time is negative.");
    if (time > 31536000)
        throw(~time, "Try to schedule a task LESS than a year from now?");
    
    // get TID and increment the TID index
    task_index = task_index + 1;
    tid = task_index;
    
    // flags can be set in a system only add_task, for now set them as 'system
    flags = ['system];
    
    // check the owner of the object sending the task
    owner = sender().owner();
    
    // do it.
    task = [tid, time, time(), sender(), caller(), method, flags, owner, args];
    ._insert_task(@task);
.