2023-04-08 13:58:47 -06:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"sync"
|
|
|
|
graphql "github.com/graph-gophers/graphql-go"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
)
|
|
|
|
|
2023-05-08 21:42:33 -06:00
|
|
|
// Generate a random graphql id
|
2023-04-08 13:58:47 -06:00
|
|
|
func gql_randid() graphql.ID{
|
|
|
|
uuid_str := uuid.New().String()
|
|
|
|
return graphql.ID(uuid_str)
|
|
|
|
}
|
|
|
|
|
2023-05-08 21:42:33 -06:00
|
|
|
// GraphNode is the interface common to both DAG nodes and Event tree nodes
|
2023-04-08 13:58:47 -06:00
|
|
|
type GraphNode interface {
|
|
|
|
Name() string
|
|
|
|
Description() string
|
|
|
|
ID() graphql.ID
|
|
|
|
UpdateListeners() error
|
|
|
|
UpdateChannel() chan error
|
|
|
|
Update() error
|
|
|
|
}
|
|
|
|
|
2023-05-08 21:42:33 -06:00
|
|
|
// BaseNode is the most basic implementation of the GraphNode interface
|
|
|
|
// It is used to implement functions common to Events and Resources
|
2023-04-08 13:58:47 -06:00
|
|
|
type BaseNode struct {
|
|
|
|
name string
|
|
|
|
description string
|
|
|
|
id graphql.ID
|
|
|
|
listeners []chan error
|
|
|
|
listeners_lock sync.Mutex
|
|
|
|
}
|
|
|
|
|
|
|
|
func (node * BaseNode) Name() string {
|
|
|
|
return node.name
|
|
|
|
}
|
|
|
|
|
|
|
|
func (node * BaseNode) Description() string {
|
|
|
|
return node.description
|
|
|
|
}
|
|
|
|
|
|
|
|
func (node * BaseNode) ID() graphql.ID {
|
|
|
|
return node.id
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a new listener channel for the node, add it to the nodes listener list, and return the new channel
|
|
|
|
func (node * BaseNode) UpdateChannel() chan error {
|
|
|
|
new_listener := make(chan error, 1)
|
|
|
|
node.listeners_lock.Lock()
|
|
|
|
node.listeners = append(node.listeners, new_listener)
|
|
|
|
node.listeners_lock.Unlock()
|
|
|
|
return new_listener
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send the update to listener channels
|
|
|
|
func (node * BaseNode) UpdateListeners() error {
|
|
|
|
closed_listeners := []int{}
|
|
|
|
listeners_closed := false
|
|
|
|
|
|
|
|
// Send each listener nil to signal it to check for new content
|
|
|
|
// if the first attempt to send it fails close the listener
|
|
|
|
node.listeners_lock.Lock()
|
|
|
|
for i, listener := range node.listeners {
|
|
|
|
select {
|
|
|
|
case listener <- nil:
|
|
|
|
default:
|
|
|
|
close(listener)
|
|
|
|
closed_listeners = append(closed_listeners, i)
|
|
|
|
listeners_closed = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If any listeners have been closed, loop over the listeners
|
|
|
|
// Add listeners to the "remaining" list if i insn't in closed_listeners
|
|
|
|
if listeners_closed == true {
|
|
|
|
remaining_listeners := []chan error{}
|
|
|
|
for i, listener := range node.listeners {
|
|
|
|
listener_closed := false
|
|
|
|
for _, index := range closed_listeners {
|
|
|
|
if index == i {
|
|
|
|
listener_closed = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if listener_closed == false {
|
|
|
|
remaining_listeners = append(remaining_listeners, listener)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
node.listeners = remaining_listeners
|
|
|
|
}
|
|
|
|
node.listeners_lock.Unlock()
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-05-08 21:42:33 -06:00
|
|
|
// Basic implementation must be overwritten to do anything useful
|
2023-04-08 13:58:47 -06:00
|
|
|
func (node * BaseNode) Update() error {
|
2023-05-08 21:42:33 -06:00
|
|
|
return errors.New("Cannot Update a BaseNode")
|
2023-04-08 13:58:47 -06:00
|
|
|
}
|