-
-
Save LaxLacks/5874db4f10499bad2fd9457d83f523b0 to your computer and use it in GitHub Desktop.
objectdef mytasks_Controller | |
{ | |
variable taskmanager TaskManager=${LMAC.NewTaskManager["mytaskstest"]} | |
method Initialize() | |
{ | |
This:AddTaskType["{\"name\":\"my first task type\",\"object\":\"MyTasks\",\"method\":\"Task_Template\"}"] | |
} | |
method Shutdown() | |
{ | |
LMAC.TaskManager["mytaskstest"]:Destroy | |
} | |
method AddTaskType(string jsonData) | |
{ | |
variable int64 id | |
id:Set[${LMAC.NewTaskType["${jsonData.Escape}"].ID}] | |
if ${id} | |
{ | |
echo "LMAC: Task Type ${id} added: ${LMAC.TaskType[${id}].Name.Escape}" | |
} | |
} | |
method Task_Template() | |
{ | |
; Task_Retarget_Wrapper checks for a supplied "target" or "targets" property. If it exists, it wraps the Task in a unicast or multicast to send to the given target(s) | |
; These lines can be removed if this Task Type should not be retargetable | |
if ${This.Task_Retarget_Wrapper[Context]} | |
return | |
; Task Types will generally do different things depending whether the TaskState is Start, Continue, or Stop. | |
; For example, Start may initialize data, Continue may update data, and Stop may clean up data | |
switch ${Context.TaskState} | |
{ | |
case Start | |
echo ${Context(type)} ${Context.Timestamp} ${Context.ElapsedMS} ${Context.Task} ${Context.TaskState} instant=${Context.Task.IsInstant} ${Context.Task.Args} | |
; Peform initialization here ... | |
break | |
case Continue | |
; echo ${Context(type)} ${Context.Timestamp} ${Context.ElapsedMS} ${Context.Task} ${Context.TaskState} instant=${Context.Task.IsInstant} ${Context.Task.Args} | |
; Perform repeating behaviors/checks here | |
break | |
case Stop | |
echo ${Context(type)} ${Context.Timestamp} ${Context.ElapsedMS} ${Context.Task} ${Context.TaskState} instant=${Context.Task.IsInstant} ${Context.Task.Args} | |
; Perform shutdown/cleanup here ... | |
break | |
} | |
} | |
; Retargets a Task, given a taskpulseargs (which comes from Context during Task execution) | |
member:uint RetargetTask(persistentref TaskPulseArgs) | |
{ | |
variable uint subTaskID | |
variable jsonvalue castTask={} | |
; Generate a copy of the Task args, without target/targets properties, to send to the target | |
variable jsonvalue innerTask | |
innerTask:SetValue["${TaskPulseArgs.Task.Args.AsJSON.Escape[0]}"] | |
innerTask:Erase["target"]:Erase["targets"] | |
; Set the "task" property to be the targetless copy | |
castTask:Set["task","${innerTask.AsJSON.Escape[0]}"] | |
; Check if we're doing unicast (single target) or multicast (any number of targets) | |
if ${TaskPulseArgs.Task.Args.Get[target](exists)} | |
{ | |
castTask:Set["type","\"unicast\""] | |
castTask:Set["target","\"${TaskPulseArgs.Task.Args.Get[target].Escape}\""] | |
} | |
elseif ${TaskPulseArgs.Task.Args.Get[targets](exists)} | |
{ | |
castTask:Set["type","\"multicast\""] | |
castTask:Set["target","\"${TaskPulseArgs.Task.Args.Get[targets].Escape}\""] | |
} | |
else | |
{ | |
; uhh.. no. | |
return 0 | |
} | |
; Now we have a unicast or multicast task, with the specified target(s), and the inner Task. Go! | |
return ${TaskPulseArgs.Task.TaskManager.BeginTask["${castTask.AsJSON.Escape[0]}"].ID} | |
} | |
; returns TRUE if the task should be retargeted, FALSE if it should not. | |
member:bool Task_Retarget_Wrapper(persistentref TaskPulseArgs) | |
{ | |
; even if there is an error, this is the only condition where we return FALSE | |
if !${TaskPulseArgs.Task.Args.Get[target](exists)} && !${TaskPulseArgs.Task.Args.Get[targets](exists)} | |
{ | |
return FALSE | |
} | |
; subTaskID will be populated with the unicast/multicast Task ID | |
variable uint subTaskID | |
switch ${TaskPulseArgs.TaskState} | |
{ | |
case Start | |
echo [Retarget] ${TaskPulseArgs(type)} ${TaskPulseArgs.Timestamp} ${TaskPulseArgs.ElapsedMS} ${TaskPulseArgs.Task} ${TaskPulseArgs.TaskState} instant=${TaskPulseArgs.Task.IsInstant} ${TaskPulseArgs.Task.Args} | |
; Here's our initialization stage | |
subTaskID:Set[${This.RetargetTask[TaskPulseArgs]}] | |
if !${subTaskID} | |
{ | |
; Well, it didn't work. | |
TaskPulseArgs:SetError["Failed to retarget Task"] | |
TaskPulseArgs.Task:Stop | |
; it SHOULD be retargeted, but it is not. we still return TRUE. | |
return TRUE | |
} | |
; task is running. update the Args with the subTaskID so we can access it in Continue and Stop states later on | |
TaskPulseArgs.Task.Args:Set["subTaskID","${subTaskID}"] | |
break | |
case Continue | |
; echo [Retarget] ${TaskPulseArgs(type)} ${TaskPulseArgs.Timestamp} ${TaskPulseArgs.ElapsedMS} ${TaskPulseArgs.Task} ${TaskPulseArgs.TaskState} instant=${TaskPulseArgs.Task.IsInstant} ${TaskPulseArgs.Task.Args} | |
; Since we added subTaskID to the Args in Start, we can retrieve it here | |
subTaskID:Set[${TaskPulseArgs.Task.Args.Get["subTaskID"]}] | |
if !${subTaskID} | |
{ | |
; sub-task is missing, this should have been handled by Start...? | |
TaskPulseArgs.Task:Stop | |
return | |
} | |
; we Continue until our subtask is no longer running | |
if !${LMAC.Task[${subTaskID}].IsRunning} | |
{ | |
; It's not running, so we can Stop now | |
TaskPulseArgs.Task:Stop | |
} | |
; continue waiting | |
break | |
case Stop | |
echo [Retarget] ${TaskPulseArgs(type)} ${TaskPulseArgs.Timestamp} ${TaskPulseArgs.ElapsedMS} ${TaskPulseArgs.Task} ${TaskPulseArgs.TaskState} instant=${TaskPulseArgs.Task.IsInstant} ${TaskPulseArgs.Task.Args} | |
; To reach this point, the subtask may already be stopped on its own, or a condition that ends this Task early (e.g. duration) is occurring and will abort the subtask. | |
; Since we added subTaskID to the Args in Start, we can retrieve it here | |
subTaskID:Set[${LMAC.Task[${taskID}].Args.Get["subTaskID"]}] | |
if ${subTaskID} | |
{ | |
; We can issue a Stop to the sub-task even if it is already stopped. If it's already stopped, this just does nothing, so it's okay. | |
LMAC.Task[${taskID}]:Stop | |
; Now that we're done with our sub-task, we can remove it from the Args so we know we don't need to touch it anymore. | |
TaskPulseArgs.Task.Args:Erase["subTaskID"] | |
} | |
break | |
} | |
return TRUE | |
} | |
; begin a test! | |
method Start() | |
{ | |
TaskManager:BeginTask["{\"type\":\"my first task type\",\"duration\":1.0,\"my setting\":\"my setting value\"}"] | |
} | |
method TestRetarget(string target, bool multicast=TRUE) | |
{ | |
if ${multicast} | |
{ | |
TaskManager:BeginTask["{\"type\":\"my first task type\",\"targets\":\"${target.Escape}\",\"duration\":1.0,\"from\":\"${Session.Escape}\"}"] | |
} | |
else | |
{ | |
TaskManager:BeginTask["{\"type\":\"my first task type\",\"target\":\"${target.Escape}\",\"duration\":1.0,\"from\":\"${Session.Escape}\"}"] | |
} | |
} | |
} | |
variable(global) mytasks_Controller MyTasks | |
function main() | |
{ | |
MyTasks:Start | |
while 1 | |
{ | |
waitframe | |
} | |
} | |
atom atexit() | |
{ | |
} |
Updated with comments.
Also added Task_Retarget_Wrapper which can be used from a Task method to automatically wrap a "target" or "targets" property into a unicast or multicast task to perform remotely. If "target" or "targets" is not provided, the original, local behavior is used.
Task_Template is updated to include this functionality.
To test the retarget wrapper code (which requires Inner Space build 6419 or later) run mytasks.iss in multiple Inner Space sessions. Then issue a command like MyTasks:TestRetarget[is1] to send to is1, or MyTasks:TestRetarget[is2] to send to is2, etc.
Example output from the sender:
[Retarget] taskpulseargs 353503687 0 161 Start instant=FALSE {"duration":1.000000,"from":"is2","targets":"is1","type":"my first task type"}
[Retarget] taskpulseargs 353504687 1000 161 Stop instant=FALSE {"duration":1.000000,"from":"is2","subTaskID":164,"targets":"is1","type":"my
first task type"}
Example output from the remote session:
taskpulseargs 353503750 0 116 Start instant=FALSE {"duration":1.000000,"from":"is2","type":"my first task type"}
taskpulseargs 353504765 1015 116 Stop instant=FALSE {"duration":1.000000,"from":"is2","type":"my first task type"}
Sample Output from running the script:
LMAC: Task Type 161 added: my first task type
taskpulseargs 271000984 0 164 Start instant=FALSE {"duration":1.000000,"my setting":"my setting value","type":"my first task type"}
taskpulseargs 271001984 1000 164 Stop instant=FALSE {"duration":1.000000,"my setting":"my setting value","type":"my first task type"}