2023-05-29 19:17:52 -06:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2023-06-03 23:49:25 -06:00
|
|
|
"time"
|
2023-05-29 19:17:52 -06:00
|
|
|
"errors"
|
|
|
|
"reflect"
|
2023-05-29 23:54:52 -06:00
|
|
|
"sort"
|
2023-06-02 17:31:29 -06:00
|
|
|
"sync"
|
2023-05-29 19:17:52 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
// Update the events listeners, and notify the parent to do the same
|
2023-06-02 17:31:29 -06:00
|
|
|
func (event * BaseEvent) update(signal GraphSignal) {
|
2023-06-01 22:42:47 -06:00
|
|
|
event.signal <- signal
|
2023-06-03 02:45:16 -06:00
|
|
|
new_signal := signal.Trace(event.ID())
|
2023-06-03 21:27:20 -06:00
|
|
|
|
|
|
|
if event.parent != nil {
|
2023-06-03 02:45:16 -06:00
|
|
|
SendUpdate(event.parent, new_signal)
|
2023-06-03 21:27:20 -06:00
|
|
|
}
|
|
|
|
|
2023-06-06 16:53:33 -06:00
|
|
|
source_id := signal.Last()
|
|
|
|
|
2023-06-03 21:27:20 -06:00
|
|
|
for _, resource := range(event.RequiredResources()) {
|
|
|
|
if source_id != resource.ID() {
|
|
|
|
SendUpdate(resource, new_signal)
|
2023-06-02 17:31:29 -06:00
|
|
|
}
|
2023-05-29 19:17:52 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type EventInfo interface {
|
|
|
|
}
|
|
|
|
|
|
|
|
type BaseEventInfo interface {
|
|
|
|
EventInfo
|
|
|
|
}
|
|
|
|
|
|
|
|
type EventQueueInfo struct {
|
|
|
|
EventInfo
|
|
|
|
priority int
|
|
|
|
state string
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewEventQueueInfo(priority int) * EventQueueInfo {
|
|
|
|
info := &EventQueueInfo{
|
|
|
|
priority: priority,
|
|
|
|
state: "queued",
|
|
|
|
}
|
|
|
|
|
|
|
|
return info
|
|
|
|
}
|
|
|
|
|
|
|
|
// Event is the interface that event tree nodes must implement
|
|
|
|
type Event interface {
|
|
|
|
GraphNode
|
|
|
|
Children() []Event
|
2023-06-02 17:31:29 -06:00
|
|
|
LockChildren()
|
|
|
|
UnlockChildren()
|
|
|
|
InfoType() reflect.Type
|
2023-05-29 19:17:52 -06:00
|
|
|
ChildInfo(event Event) EventInfo
|
|
|
|
Parent() Event
|
2023-06-02 17:31:29 -06:00
|
|
|
LockParent()
|
|
|
|
UnlockParent()
|
|
|
|
Action(action string) (func()(string, error), bool)
|
2023-06-03 01:38:35 -06:00
|
|
|
Handler(signal_type string) (func(GraphSignal) (string, error), bool)
|
2023-05-29 19:17:52 -06:00
|
|
|
RequiredResources() []Resource
|
2023-05-29 23:54:52 -06:00
|
|
|
DoneResource() Resource
|
2023-06-03 23:49:25 -06:00
|
|
|
SetTimeout(end_time time.Time, action string)
|
|
|
|
Timeout() <-chan time.Time
|
|
|
|
TimeoutAction() string
|
|
|
|
Signal() chan GraphSignal
|
2023-06-02 17:31:29 -06:00
|
|
|
|
|
|
|
finish() error
|
|
|
|
|
|
|
|
addChild(child Event, info EventInfo)
|
|
|
|
setParent(parent Event)
|
2023-05-29 19:17:52 -06:00
|
|
|
}
|
|
|
|
|
2023-06-03 23:49:25 -06:00
|
|
|
func (event * BaseEvent) Signal() chan GraphSignal {
|
|
|
|
return event.signal
|
|
|
|
}
|
|
|
|
|
|
|
|
func (event * BaseEvent) TimeoutAction() string {
|
|
|
|
return event.timeout_action
|
|
|
|
}
|
|
|
|
|
|
|
|
func (event * BaseEvent) Timeout() <-chan time.Time {
|
|
|
|
return event.timeout
|
|
|
|
}
|
|
|
|
|
|
|
|
func (event * BaseEvent) SetTimeout(end_time time.Time, action string) {
|
|
|
|
event.timeout_action = action
|
|
|
|
event.timeout = time.After(time.Until(end_time))
|
|
|
|
}
|
|
|
|
|
2023-06-03 01:38:35 -06:00
|
|
|
func (event * BaseEvent) Handler(signal_type string) (func(GraphSignal)(string, error), bool) {
|
2023-06-02 17:31:29 -06:00
|
|
|
handler, exists := event.handlers[signal_type]
|
|
|
|
return handler, exists
|
|
|
|
}
|
|
|
|
|
2023-06-16 18:27:03 -06:00
|
|
|
func FindResources(event Event, resource_type reflect.Type) []Resource {
|
|
|
|
resources := event.RequiredResources()
|
|
|
|
found := []Resource{}
|
|
|
|
for _, resource := range(resources) {
|
|
|
|
if reflect.TypeOf(resource) == resource_type {
|
|
|
|
found = append(found, resource)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, child := range(event.Children()) {
|
|
|
|
found = append(found, FindResources(child, resource_type)...)
|
|
|
|
}
|
|
|
|
|
|
|
|
m := map[string]Resource{}
|
|
|
|
for _, resource := range(found) {
|
|
|
|
m[resource.ID()] = resource
|
|
|
|
}
|
|
|
|
ret := []Resource{}
|
|
|
|
for _, resource := range(m) {
|
|
|
|
ret = append(ret, resource)
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
func FindRequiredResource(event Event, id string) Resource {
|
|
|
|
for _, resource := range(event.RequiredResources()) {
|
|
|
|
if resource.ID() == id {
|
|
|
|
return resource
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, child := range(event.Children()) {
|
|
|
|
result := FindRequiredResource(child, id)
|
|
|
|
if result != nil {
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
func FindChild(event Event, id string) Event {
|
|
|
|
if id == event.ID() {
|
|
|
|
return event
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, child := range event.Children() {
|
|
|
|
result := FindChild(child, id)
|
|
|
|
if result != nil {
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func CheckInfoType(event Event, info EventInfo) bool {
|
|
|
|
if event.InfoType() == nil || info == nil {
|
|
|
|
if event.InfoType() == nil && info == nil {
|
|
|
|
return true
|
|
|
|
} else {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return event.InfoType() == reflect.TypeOf(info)
|
2023-05-29 23:54:52 -06:00
|
|
|
}
|
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
func AddChild(event Event, child Event, info EventInfo) error {
|
|
|
|
if CheckInfoType(event, info) == false {
|
|
|
|
return errors.New("AddChild got wrong type")
|
|
|
|
}
|
|
|
|
|
|
|
|
event.LockParent()
|
2023-06-04 14:15:01 -06:00
|
|
|
child.LockParent()
|
|
|
|
if child.Parent() != nil {
|
|
|
|
child.UnlockParent()
|
2023-06-02 17:31:29 -06:00
|
|
|
event.UnlockParent()
|
2023-06-04 14:15:26 -06:00
|
|
|
return errors.New(fmt.Sprintf("Parent already registered: %s->%s already %s", child.Name(), event.Name(), child.Parent().Name()))
|
2023-05-30 20:45:16 -06:00
|
|
|
}
|
2023-06-02 17:31:29 -06:00
|
|
|
|
|
|
|
event.LockChildren()
|
|
|
|
|
|
|
|
for _, c := range(event.Children()) {
|
|
|
|
if c.ID() == child.ID() {
|
|
|
|
event.UnlockChildren()
|
2023-06-04 14:15:01 -06:00
|
|
|
child.UnlockParent()
|
2023-06-02 17:31:29 -06:00
|
|
|
event.UnlockParent()
|
|
|
|
return errors.New("Child already in event")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// After all the checks are done, update the state of child + parent, then unlock and update
|
|
|
|
child.setParent(event)
|
|
|
|
event.addChild(child, info)
|
|
|
|
|
|
|
|
event.UnlockChildren()
|
2023-06-04 14:15:01 -06:00
|
|
|
child.UnlockParent()
|
2023-06-02 17:31:29 -06:00
|
|
|
event.UnlockParent()
|
|
|
|
|
2023-06-03 01:38:35 -06:00
|
|
|
update := NewSignal(event, "child_added")
|
|
|
|
update.description = child.Name()
|
2023-06-02 17:31:29 -06:00
|
|
|
SendUpdate(event, NewSignal(event, "child_added"))
|
2023-05-29 23:54:52 -06:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
func RunEvent(event Event) error {
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("event", "EVENT_RUN: %s", event.Name())
|
2023-06-03 01:38:35 -06:00
|
|
|
go SendUpdate(event, NewSignal(event, "event_start"))
|
2023-06-02 17:31:29 -06:00
|
|
|
next_action := "start"
|
|
|
|
var err error = nil
|
|
|
|
for next_action != "" {
|
|
|
|
action, exists := event.Action(next_action)
|
|
|
|
if exists == false {
|
|
|
|
error_str := fmt.Sprintf("%s is not a valid action", next_action)
|
|
|
|
return errors.New(error_str)
|
|
|
|
}
|
|
|
|
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("event", "EVENT_ACTION: %s - %s", event.Name(), next_action)
|
2023-06-02 17:31:29 -06:00
|
|
|
next_action, err = action()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("event", "EVENT_RUN_DONE: %s", event.Name())
|
2023-06-02 17:31:29 -06:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-06-06 23:04:49 -06:00
|
|
|
func EventAbort(event Event) func(signal GraphSignal) (string, error) {
|
|
|
|
return func(signal GraphSignal) (string, error) {
|
|
|
|
if signal.Description() == event.ID() {
|
|
|
|
AbortChildren(event)
|
|
|
|
return "", errors.New(fmt.Sprintf("%s aborted by signal", event.ID()))
|
|
|
|
}
|
|
|
|
return "wait", nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func EventCancel(event Event) func(signal GraphSignal) (string, error) {
|
|
|
|
return func(signal GraphSignal) (string, error) {
|
|
|
|
if signal.Description() == event.ID() {
|
|
|
|
CancelChildren(event)
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
return "wait", nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func CancelChildren(event Event) {
|
2023-06-03 21:27:20 -06:00
|
|
|
event.LockChildren()
|
|
|
|
for _, child := range(event.Children()) {
|
2023-06-06 23:04:49 -06:00
|
|
|
signal := NewSignal(event, "cancel")
|
|
|
|
signal.description = child.ID()
|
|
|
|
SendUpdate(child, signal)
|
|
|
|
}
|
|
|
|
event.UnlockChildren()
|
|
|
|
}
|
|
|
|
|
|
|
|
func AbortChildren(event Event) {
|
|
|
|
event.LockChildren()
|
|
|
|
for _, child := range(event.Children()) {
|
|
|
|
signal := NewSignal(event, "abort")
|
|
|
|
signal.description = child.ID()
|
|
|
|
SendUpdate(child, signal)
|
2023-06-03 21:27:20 -06:00
|
|
|
}
|
|
|
|
event.UnlockChildren()
|
2023-06-02 17:31:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func LockResources(event Event) error {
|
2023-06-07 00:36:40 -06:00
|
|
|
log.Logf("event", "RESOURCE_LOCKING for %s - %+v", event.Name(), event.RequiredResources())
|
2023-05-29 23:54:52 -06:00
|
|
|
locked_resources := []Resource{}
|
2023-06-01 13:11:32 -06:00
|
|
|
var lock_err error = nil
|
2023-05-29 23:54:52 -06:00
|
|
|
for _, resource := range(event.RequiredResources()) {
|
2023-06-02 17:31:29 -06:00
|
|
|
err := LockResource(resource, event)
|
2023-05-29 23:54:52 -06:00
|
|
|
if err != nil {
|
2023-06-01 13:11:32 -06:00
|
|
|
lock_err = err
|
|
|
|
break
|
2023-05-29 23:54:52 -06:00
|
|
|
}
|
2023-05-30 00:00:14 -06:00
|
|
|
locked_resources = append(locked_resources, resource)
|
2023-05-29 23:54:52 -06:00
|
|
|
}
|
|
|
|
|
2023-06-01 13:11:32 -06:00
|
|
|
if lock_err != nil {
|
2023-05-29 23:54:52 -06:00
|
|
|
for _, resource := range(locked_resources) {
|
2023-06-02 17:31:29 -06:00
|
|
|
UnlockResource(resource, event)
|
2023-05-29 23:54:52 -06:00
|
|
|
}
|
2023-06-01 13:11:32 -06:00
|
|
|
return lock_err
|
2023-06-02 17:31:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, resource := range(locked_resources) {
|
|
|
|
NotifyResourceLocked(resource)
|
2023-05-29 23:54:52 -06:00
|
|
|
}
|
2023-06-01 13:11:32 -06:00
|
|
|
|
2023-05-29 23:54:52 -06:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
func FinishEvent(event Event) error {
|
|
|
|
// TODO make more 'safe' like LockResources, or make UnlockResource not return errors
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("event", "EVENT_FINISH: %s", event.Name())
|
2023-05-30 00:00:14 -06:00
|
|
|
for _, resource := range(event.RequiredResources()) {
|
2023-06-02 17:31:29 -06:00
|
|
|
err := UnlockResource(resource, event)
|
2023-05-30 00:00:14 -06:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2023-06-02 17:31:29 -06:00
|
|
|
NotifyResourceUnlocked(resource)
|
2023-05-30 00:00:14 -06:00
|
|
|
}
|
2023-06-01 22:42:47 -06:00
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
err := UnlockResource(event.DoneResource(), event)
|
2023-06-01 13:48:38 -06:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-06-01 22:42:47 -06:00
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
NotifyResourceUnlocked(event.DoneResource())
|
2023-06-01 22:42:47 -06:00
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
err = event.finish()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-06-01 22:42:47 -06:00
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
SendUpdate(event, NewSignal(event, "event_done"))
|
|
|
|
return nil
|
2023-05-29 23:54:52 -06:00
|
|
|
}
|
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
// BaseEvent is the most basic event that can exist in the event tree.
|
|
|
|
// On start it automatically transitions to completion.
|
|
|
|
// It can optionally require events, which will all need to be locked to start it
|
|
|
|
// It can optionally create resources, which will be locked by default and unlocked on completion
|
|
|
|
// This node by itself doesn't implement any special behaviours for children, so they will be ignored.
|
|
|
|
// When starter, this event automatically transitions to completion and unlocks all it's resources(including created)
|
|
|
|
type BaseEvent struct {
|
|
|
|
BaseNode
|
|
|
|
done_resource Resource
|
|
|
|
required_resources []Resource
|
|
|
|
children []Event
|
|
|
|
child_info map[string]EventInfo
|
|
|
|
child_lock sync.Mutex
|
|
|
|
actions map[string]func() (string, error)
|
2023-06-03 01:38:35 -06:00
|
|
|
handlers map[string]func(GraphSignal) (string, error)
|
2023-06-02 17:31:29 -06:00
|
|
|
parent Event
|
|
|
|
parent_lock sync.Mutex
|
|
|
|
abort chan string
|
2023-06-03 23:49:25 -06:00
|
|
|
timeout <-chan time.Time
|
|
|
|
timeout_action string
|
2023-05-30 20:45:16 -06:00
|
|
|
}
|
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
func (event * BaseEvent) Action(action string) (func() (string, error), bool) {
|
|
|
|
action_fn, exists := event.actions[action]
|
|
|
|
return action_fn, exists
|
2023-05-29 19:17:52 -06:00
|
|
|
}
|
|
|
|
|
2023-06-03 23:49:25 -06:00
|
|
|
func EventWait(event Event) (func() (string, error)) {
|
|
|
|
return func() (string, error) {
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("event", "EVENT_WAIT: %s TIMEOUT: %+v", event.Name(), event.Timeout())
|
2023-06-03 23:49:25 -06:00
|
|
|
select {
|
|
|
|
case signal := <- event.Signal():
|
|
|
|
if signal.Source() != nil {
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("event", "EVENT_SIGNAL: %s %s %s -> %+v", event.Name(), signal.Last(), signal.Source().Name(), signal)
|
2023-06-03 23:49:25 -06:00
|
|
|
} else {
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("event", "EVENT_SIGNAL: %s %s nil -> %+v", event.Name(), signal.Last(), signal)
|
2023-06-03 23:49:25 -06:00
|
|
|
}
|
2023-06-06 23:04:49 -06:00
|
|
|
signal_fn, exists := event.Handler(signal.Type())
|
|
|
|
if exists == true {
|
|
|
|
log.Logf("event", "EVENT_HANDLER: %s - %s", event.Name(), signal.Type())
|
|
|
|
return signal_fn(signal)
|
2023-06-03 23:49:25 -06:00
|
|
|
}
|
|
|
|
return "wait", nil
|
|
|
|
case <- event.Timeout():
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("event", "EVENT_TIMEOUT %s - NEXT_STATE: %s", event.Name(), event.TimeoutAction())
|
2023-06-03 23:49:25 -06:00
|
|
|
return event.TimeoutAction(), nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-30 20:45:16 -06:00
|
|
|
func NewBaseEvent(name string, description string, required_resources []Resource) (BaseEvent) {
|
2023-05-29 19:17:52 -06:00
|
|
|
done_resource := NewResource("event_done", "signal that event is done", []Resource{})
|
2023-05-30 20:45:16 -06:00
|
|
|
event := BaseEvent{
|
2023-06-03 18:56:14 -06:00
|
|
|
BaseNode: NewBaseNode(name, description, randid()),
|
2023-05-29 19:17:52 -06:00
|
|
|
parent: nil,
|
|
|
|
children: []Event{},
|
2023-06-02 17:31:29 -06:00
|
|
|
child_info: map[string]EventInfo{},
|
2023-05-29 23:54:52 -06:00
|
|
|
done_resource: done_resource,
|
2023-05-29 19:17:52 -06:00
|
|
|
required_resources: required_resources,
|
2023-05-30 21:50:59 -06:00
|
|
|
actions: map[string]func()(string, error){},
|
2023-06-03 01:38:35 -06:00
|
|
|
handlers: map[string]func(GraphSignal)(string, error){},
|
2023-05-30 20:45:16 -06:00
|
|
|
abort: make(chan string, 1),
|
2023-06-03 23:49:25 -06:00
|
|
|
timeout: nil,
|
|
|
|
timeout_action: "",
|
2023-05-29 19:17:52 -06:00
|
|
|
}
|
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
LockResource(event.done_resource, &event)
|
|
|
|
|
2023-05-30 20:45:16 -06:00
|
|
|
return event
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewEvent(name string, description string, required_resources []Resource) (* BaseEvent) {
|
|
|
|
event := NewBaseEvent(name, description, required_resources)
|
|
|
|
event_ptr := &event
|
|
|
|
|
2023-06-03 23:49:25 -06:00
|
|
|
event_ptr.actions["wait"] = EventWait(event_ptr)
|
2023-06-06 23:04:49 -06:00
|
|
|
event_ptr.handlers["abort"] = EventAbort(event_ptr)
|
|
|
|
event_ptr.handlers["cancel"] = EventCancel(event_ptr)
|
2023-06-03 23:49:25 -06:00
|
|
|
|
2023-05-30 21:50:59 -06:00
|
|
|
event_ptr.actions["start"] = func() (string, error) {
|
2023-05-29 23:54:52 -06:00
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
|
2023-05-30 20:45:16 -06:00
|
|
|
return event_ptr
|
2023-05-29 19:17:52 -06:00
|
|
|
}
|
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
func (event * BaseEvent) finish() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (event * BaseEvent) InfoType() reflect.Type {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-06-01 22:42:47 -06:00
|
|
|
// EventQueue is a basic event that can have children.
|
|
|
|
// On start, it attempts to start it's children from the highest 'priority'
|
|
|
|
type EventQueue struct {
|
|
|
|
BaseEvent
|
|
|
|
listened_resources map[string]Resource
|
2023-06-02 17:31:29 -06:00
|
|
|
queue_lock sync.Mutex
|
2023-06-01 22:42:47 -06:00
|
|
|
}
|
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
func (queue * EventQueue) finish() error {
|
2023-06-01 22:42:47 -06:00
|
|
|
for _, resource := range(queue.listened_resources) {
|
|
|
|
resource.UnregisterChannel(queue.signal)
|
|
|
|
}
|
2023-06-02 17:31:29 -06:00
|
|
|
return nil
|
2023-06-01 22:42:47 -06:00
|
|
|
}
|
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
func (queue * EventQueue) InfoType() reflect.Type {
|
|
|
|
return reflect.TypeOf((*EventQueueInfo)(nil))
|
|
|
|
}
|
2023-06-01 22:42:47 -06:00
|
|
|
|
2023-05-29 23:54:52 -06:00
|
|
|
func NewEventQueue(name string, description string, required_resources []Resource) (* EventQueue) {
|
2023-05-29 19:17:52 -06:00
|
|
|
queue := &EventQueue{
|
2023-06-07 00:36:40 -06:00
|
|
|
BaseEvent: NewBaseEvent(name, description, required_resources),
|
2023-06-01 22:42:47 -06:00
|
|
|
listened_resources: map[string]Resource{},
|
2023-05-29 19:17:52 -06:00
|
|
|
}
|
|
|
|
|
2023-06-03 23:49:25 -06:00
|
|
|
queue.actions["wait"] = EventWait(queue)
|
2023-06-06 23:04:49 -06:00
|
|
|
queue.handlers["abort"] = EventAbort(queue)
|
|
|
|
queue.handlers["cancel"] = EventCancel(queue)
|
2023-06-03 23:49:25 -06:00
|
|
|
|
2023-05-30 21:50:59 -06:00
|
|
|
queue.actions["start"] = func() (string, error) {
|
2023-05-29 23:54:52 -06:00
|
|
|
return "queue_event", nil
|
|
|
|
}
|
|
|
|
|
2023-05-30 21:50:59 -06:00
|
|
|
queue.actions["queue_event"] = func() (string, error) {
|
2023-05-30 00:00:14 -06:00
|
|
|
// Copy the events to sort the list
|
2023-06-02 17:31:29 -06:00
|
|
|
queue.LockChildren()
|
2023-05-29 23:54:52 -06:00
|
|
|
copied_events := make([]Event, len(queue.Children()))
|
|
|
|
copy(copied_events, queue.Children())
|
|
|
|
less := func(i int, j int) bool {
|
|
|
|
info_i := queue.ChildInfo(copied_events[i]).(*EventQueueInfo)
|
|
|
|
info_j := queue.ChildInfo(copied_events[j]).(*EventQueueInfo)
|
|
|
|
return info_i.priority < info_j.priority
|
|
|
|
}
|
|
|
|
sort.SliceStable(copied_events, less)
|
|
|
|
|
2023-06-01 22:42:47 -06:00
|
|
|
needed_resources := map[string]Resource{}
|
2023-05-29 23:54:52 -06:00
|
|
|
for _, event := range(copied_events) {
|
2023-06-01 22:42:47 -06:00
|
|
|
// make sure all the required resources are registered to update the event
|
2023-06-01 13:11:32 -06:00
|
|
|
for _, resource := range(event.RequiredResources()) {
|
2023-06-01 22:42:47 -06:00
|
|
|
needed_resources[resource.ID()] = resource
|
2023-06-01 13:11:32 -06:00
|
|
|
}
|
|
|
|
|
2023-05-29 23:54:52 -06:00
|
|
|
info := queue.ChildInfo(event).(*EventQueueInfo)
|
|
|
|
if info.state == "queued" {
|
|
|
|
// Try to lock it
|
2023-06-02 17:31:29 -06:00
|
|
|
err := LockResources(event)
|
2023-05-29 23:54:52 -06:00
|
|
|
// start in new goroutine
|
|
|
|
if err != nil {
|
2023-06-04 13:18:10 -06:00
|
|
|
//log.Logf("event", "Failed to lock %s: %s", event.Name(), err)
|
2023-05-29 23:54:52 -06:00
|
|
|
} else {
|
|
|
|
info.state = "running"
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("event", "EVENT_START: %s", event.Name())
|
2023-05-30 20:45:16 -06:00
|
|
|
go func(event Event, info * EventQueueInfo, queue Event) {
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("event", "EVENT_GOROUTINE: %s", event.Name())
|
2023-06-02 17:31:29 -06:00
|
|
|
err := RunEvent(event)
|
2023-06-01 13:11:32 -06:00
|
|
|
if err != nil {
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("event", "EVENT_ERROR: %s", err)
|
2023-06-01 13:11:32 -06:00
|
|
|
}
|
2023-05-29 23:54:52 -06:00
|
|
|
info.state = "done"
|
2023-06-02 17:31:29 -06:00
|
|
|
FinishEvent(event)
|
2023-05-29 23:54:52 -06:00
|
|
|
}(event, info, queue)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
|
2023-06-01 22:42:47 -06:00
|
|
|
for _, resource := range(needed_resources) {
|
2023-06-03 01:38:35 -06:00
|
|
|
_, exists := queue.listened_resources[resource.ID()]
|
|
|
|
if exists == false {
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("event", "REGISTER_RESOURCE: %s - %s", queue.Name(), resource.Name())
|
2023-06-03 01:38:35 -06:00
|
|
|
queue.listened_resources[resource.ID()] = resource
|
|
|
|
resource.RegisterChannel(queue.signal)
|
|
|
|
}
|
2023-06-01 22:42:47 -06:00
|
|
|
}
|
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
queue.UnlockChildren()
|
|
|
|
|
2023-06-06 23:04:49 -06:00
|
|
|
return "wait", nil
|
2023-05-29 23:54:52 -06:00
|
|
|
}
|
|
|
|
|
2023-06-03 10:59:42 -06:00
|
|
|
queue.handlers["resource_connected"] = func(signal GraphSignal) (string, error) {
|
2023-06-03 01:38:35 -06:00
|
|
|
return "queue_event", nil
|
|
|
|
}
|
|
|
|
|
|
|
|
queue.handlers["child_added"] = func(signal GraphSignal) (string, error) {
|
2023-05-29 23:54:52 -06:00
|
|
|
return "queue_event", nil
|
|
|
|
}
|
2023-05-29 19:17:52 -06:00
|
|
|
|
2023-06-03 01:38:35 -06:00
|
|
|
queue.handlers["lock_changed"] = func(signal GraphSignal) (string, error) {
|
2023-06-01 22:42:47 -06:00
|
|
|
return "queue_event", nil
|
|
|
|
}
|
|
|
|
|
2023-06-03 01:38:35 -06:00
|
|
|
queue.handlers["event_done"] = func(signal GraphSignal) (string, error) {
|
2023-06-01 22:42:47 -06:00
|
|
|
return "queue_event", nil
|
|
|
|
}
|
|
|
|
|
2023-05-29 23:54:52 -06:00
|
|
|
return queue
|
2023-05-29 19:17:52 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (event * BaseEvent) Parent() Event {
|
|
|
|
return event.parent
|
|
|
|
}
|
|
|
|
|
|
|
|
func (event * BaseEvent) RequiredResources() []Resource {
|
|
|
|
return event.required_resources
|
|
|
|
}
|
|
|
|
|
2023-05-29 23:54:52 -06:00
|
|
|
func (event * BaseEvent) DoneResource() Resource {
|
|
|
|
return event.done_resource
|
2023-05-29 19:17:52 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (event * BaseEvent) Children() []Event {
|
|
|
|
return event.children
|
|
|
|
}
|
|
|
|
|
|
|
|
func (event * BaseEvent) ChildInfo(idx Event) EventInfo {
|
2023-06-02 17:31:29 -06:00
|
|
|
val, ok := event.child_info[idx.ID()]
|
2023-05-29 19:17:52 -06:00
|
|
|
if ok == false {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return val
|
|
|
|
}
|
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
func (event * BaseEvent) LockChildren() {
|
|
|
|
event.child_lock.Lock()
|
2023-05-29 19:17:52 -06:00
|
|
|
}
|
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
func (event * BaseEvent) UnlockChildren() {
|
|
|
|
event.child_lock.Unlock()
|
2023-05-29 19:17:52 -06:00
|
|
|
}
|
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
func (event * BaseEvent) LockParent() {
|
|
|
|
event.parent_lock.Lock()
|
2023-05-29 19:17:52 -06:00
|
|
|
}
|
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
func (event * BaseEvent) UnlockParent() {
|
|
|
|
event.parent_lock.Unlock()
|
2023-05-29 19:17:52 -06:00
|
|
|
}
|
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
func (event * BaseEvent) setParent(parent Event) {
|
|
|
|
event.parent = parent
|
|
|
|
}
|
2023-05-29 19:17:52 -06:00
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
func (event * BaseEvent) addChild(child Event, info EventInfo) {
|
|
|
|
event.children = append(event.children, child)
|
|
|
|
event.child_info[child.ID()] = info
|
2023-05-29 19:17:52 -06:00
|
|
|
}
|
2023-06-06 23:04:49 -06:00
|
|
|
|
|
|
|
type GQLEvent struct {
|
|
|
|
BaseEvent
|
|
|
|
abort chan error
|
|
|
|
}
|