2023-06-18 18:33:17 -06:00
|
|
|
package graphvent
|
2023-04-08 13:58:47 -06:00
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
"github.com/google/uuid"
|
2023-06-03 01:38:35 -06:00
|
|
|
"time"
|
2023-06-04 13:18:10 -06:00
|
|
|
"os"
|
|
|
|
"github.com/rs/zerolog"
|
|
|
|
"fmt"
|
2023-04-08 13:58:47 -06:00
|
|
|
)
|
|
|
|
|
2023-06-04 13:18:10 -06:00
|
|
|
type Logger interface {
|
|
|
|
Init() error
|
|
|
|
Logf(component string, format string, items ... interface{})
|
2023-06-08 16:41:51 -06:00
|
|
|
Logm(component string, fields map[string]interface{}, format string, items ... interface{})
|
2023-06-04 13:18:10 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
type DefaultLogger struct {
|
|
|
|
init_lock sync.Mutex
|
2023-06-18 18:54:06 -06:00
|
|
|
Loggers map[string]zerolog.Logger
|
|
|
|
Components []string
|
2023-06-04 13:18:10 -06:00
|
|
|
}
|
|
|
|
|
2023-06-20 16:35:16 -06:00
|
|
|
var Log DefaultLogger = DefaultLogger{Loggers: map[string]zerolog.Logger{}, Components: []string{}}
|
2023-06-04 13:18:10 -06:00
|
|
|
|
|
|
|
func (logger * DefaultLogger) Init(components []string) error {
|
2023-06-08 16:41:51 -06:00
|
|
|
logger.init_lock.Lock()
|
|
|
|
defer logger.init_lock.Unlock()
|
|
|
|
|
2023-06-04 13:18:10 -06:00
|
|
|
component_enabled := func (component string) bool {
|
|
|
|
for _, c := range(components) {
|
|
|
|
if c == component {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2023-06-20 16:35:16 -06:00
|
|
|
for c, _ := range(logger.Loggers) {
|
|
|
|
if component_enabled(c) == false {
|
|
|
|
delete(logger.Loggers, c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range(components) {
|
|
|
|
_, exists := logger.Loggers[c]
|
|
|
|
if component_enabled(c) == true && exists == false {
|
|
|
|
logger.Loggers[c] = zerolog.New(os.Stdout).With().Timestamp().Str("component", c).Logger()
|
2023-06-04 13:18:10 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-06-08 16:41:51 -06:00
|
|
|
func (logger * DefaultLogger) Logm(component string, fields map[string]interface{}, format string, items ... interface{}) {
|
2023-06-18 18:54:06 -06:00
|
|
|
l, exists := logger.Loggers[component]
|
2023-06-08 16:41:51 -06:00
|
|
|
if exists == true {
|
|
|
|
log := l.Log()
|
|
|
|
for key, value := range(fields) {
|
|
|
|
log = log.Str(key, fmt.Sprintf("%+v", value))
|
|
|
|
}
|
|
|
|
log.Msg(fmt.Sprintf(format, items...))
|
2023-06-04 13:18:10 -06:00
|
|
|
}
|
2023-06-08 16:41:51 -06:00
|
|
|
}
|
2023-06-04 13:18:10 -06:00
|
|
|
|
2023-06-08 16:41:51 -06:00
|
|
|
func (logger * DefaultLogger) Logf(component string, format string, items ... interface{}) {
|
2023-06-18 18:54:06 -06:00
|
|
|
l, exists := logger.Loggers[component]
|
2023-06-04 13:18:10 -06:00
|
|
|
if exists == true {
|
|
|
|
l.Log().Msg(fmt.Sprintf(format, items...))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-08 21:42:33 -06:00
|
|
|
// Generate a random graphql id
|
2023-05-31 00:37:51 -06:00
|
|
|
func randid() string{
|
2023-04-08 13:58:47 -06:00
|
|
|
uuid_str := uuid.New().String()
|
2023-05-31 00:37:51 -06:00
|
|
|
return uuid_str
|
2023-04-08 13:58:47 -06:00
|
|
|
}
|
|
|
|
|
2023-06-01 22:42:47 -06:00
|
|
|
type GraphSignal interface {
|
2023-06-18 18:11:59 -06:00
|
|
|
Downwards() bool
|
|
|
|
Source() string
|
2023-06-01 22:42:47 -06:00
|
|
|
Type() string
|
2023-06-04 17:23:49 -06:00
|
|
|
String() string
|
2023-06-01 22:42:47 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
type BaseSignal struct {
|
2023-06-18 18:11:59 -06:00
|
|
|
downwards bool
|
|
|
|
source string
|
|
|
|
_type string
|
2023-06-04 17:23:49 -06:00
|
|
|
}
|
|
|
|
|
2023-06-18 18:11:59 -06:00
|
|
|
func (signal BaseSignal) Downwards() bool {
|
|
|
|
return signal.downwards
|
2023-06-01 22:42:47 -06:00
|
|
|
}
|
|
|
|
|
2023-06-18 18:11:59 -06:00
|
|
|
func (signal BaseSignal) Source() string {
|
2023-06-01 22:42:47 -06:00
|
|
|
return signal.source
|
|
|
|
}
|
|
|
|
|
|
|
|
func (signal BaseSignal) Type() string {
|
2023-06-18 18:11:59 -06:00
|
|
|
return signal._type
|
2023-06-01 22:42:47 -06:00
|
|
|
}
|
|
|
|
|
2023-06-18 18:11:59 -06:00
|
|
|
func (signal BaseSignal) String() string {
|
|
|
|
return fmt.Sprintf("{downwards: %t, source: %s, type: %s}", signal.downwards, signal.source, signal._type)
|
2023-06-01 22:42:47 -06:00
|
|
|
}
|
|
|
|
|
2023-06-18 18:11:59 -06:00
|
|
|
type TimeSignal struct {
|
|
|
|
BaseSignal
|
|
|
|
time time.Time
|
2023-06-03 02:45:16 -06:00
|
|
|
}
|
|
|
|
|
2023-06-19 15:03:17 -06:00
|
|
|
func NewBaseSignal(source GraphNode, _type string, downwards bool) BaseSignal {
|
2023-06-18 18:11:59 -06:00
|
|
|
source_id := ""
|
|
|
|
if source != nil {
|
|
|
|
source_id = source.ID()
|
|
|
|
}
|
|
|
|
|
|
|
|
signal := BaseSignal{
|
2023-06-19 15:03:17 -06:00
|
|
|
downwards: downwards,
|
2023-06-18 18:11:59 -06:00
|
|
|
source: source_id,
|
|
|
|
_type: _type,
|
|
|
|
}
|
|
|
|
return signal
|
2023-06-03 02:45:16 -06:00
|
|
|
}
|
|
|
|
|
2023-06-19 15:03:17 -06:00
|
|
|
func NewDownSignal(source GraphNode, _type string) BaseSignal {
|
|
|
|
return NewBaseSignal(source, _type, true)
|
|
|
|
}
|
2023-06-18 18:11:59 -06:00
|
|
|
|
2023-06-19 15:03:17 -06:00
|
|
|
func NewSignal(source GraphNode, _type string) BaseSignal {
|
|
|
|
return NewBaseSignal(source, _type, false)
|
2023-06-01 22:42:47 -06:00
|
|
|
}
|
|
|
|
|
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
|
2023-05-31 00:37:51 -06:00
|
|
|
ID() string
|
2023-06-20 22:36:18 -06:00
|
|
|
Allowed() []GraphNode
|
|
|
|
Delegator(id string) GraphNode
|
|
|
|
TakeLock(resource Resource)
|
2023-06-02 17:31:29 -06:00
|
|
|
UpdateListeners(update GraphSignal)
|
2023-06-18 19:14:07 -06:00
|
|
|
PropagateUpdate(update GraphSignal)
|
2023-06-01 22:42:47 -06:00
|
|
|
RegisterChannel(listener chan GraphSignal)
|
|
|
|
UnregisterChannel(listener chan GraphSignal)
|
|
|
|
UpdateChannel() chan GraphSignal
|
2023-06-18 19:18:11 -06:00
|
|
|
SignalChannel() chan GraphSignal
|
2023-04-08 13:58:47 -06:00
|
|
|
}
|
|
|
|
|
2023-06-03 18:56:14 -06:00
|
|
|
func NewBaseNode(name string, description string, id string) BaseNode {
|
|
|
|
node := BaseNode{
|
|
|
|
name: name,
|
|
|
|
description: description,
|
|
|
|
id: id,
|
2023-06-04 17:23:49 -06:00
|
|
|
signal: make(chan GraphSignal, 512),
|
2023-06-03 18:56:14 -06:00
|
|
|
listeners: map[chan GraphSignal]chan GraphSignal{},
|
2023-06-20 22:36:18 -06:00
|
|
|
delegation_map: map[string]GraphNode{},
|
2023-06-03 18:56:14 -06:00
|
|
|
}
|
2023-06-20 16:35:16 -06:00
|
|
|
Log.Logf("graph", "NEW_NODE: %s - %s", node.ID(), node.Name())
|
2023-06-03 18:56:14 -06:00
|
|
|
return node
|
|
|
|
}
|
|
|
|
|
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
|
2023-05-31 00:37:51 -06:00
|
|
|
id string
|
2023-06-01 22:42:47 -06:00
|
|
|
signal chan GraphSignal
|
2023-04-08 13:58:47 -06:00
|
|
|
listeners_lock sync.Mutex
|
2023-06-01 22:42:47 -06:00
|
|
|
listeners map[chan GraphSignal]chan GraphSignal
|
2023-06-20 22:36:18 -06:00
|
|
|
delegation_map map[string]GraphNode
|
|
|
|
}
|
|
|
|
|
|
|
|
func (node * BaseNode) TakeLock(resource Resource) {
|
|
|
|
_, exists := node.delegation_map[resource.ID()]
|
|
|
|
if exists == true {
|
|
|
|
panic("Trying to take a lock we already have")
|
|
|
|
}
|
|
|
|
|
|
|
|
node.delegation_map[resource.ID()] = resource.Owner()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (node * BaseNode) Allowed() []GraphNode {
|
|
|
|
return []GraphNode{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (node * BaseNode) Delegator(id string) GraphNode {
|
|
|
|
last_owner, exists := node.delegation_map[id]
|
|
|
|
if exists == false {
|
|
|
|
panic("Trying to delegate a lock we don't own")
|
|
|
|
}
|
|
|
|
|
|
|
|
delete(node.delegation_map, id)
|
|
|
|
return last_owner
|
2023-04-08 13:58:47 -06:00
|
|
|
}
|
|
|
|
|
2023-06-18 19:18:11 -06:00
|
|
|
func (node * BaseNode) SignalChannel() chan GraphSignal {
|
|
|
|
return node.signal
|
2023-06-18 19:16:11 -06:00
|
|
|
}
|
|
|
|
|
2023-04-08 13:58:47 -06:00
|
|
|
func (node * BaseNode) Name() string {
|
|
|
|
return node.name
|
|
|
|
}
|
|
|
|
|
|
|
|
func (node * BaseNode) Description() string {
|
|
|
|
return node.description
|
|
|
|
}
|
|
|
|
|
2023-05-31 00:37:51 -06:00
|
|
|
func (node * BaseNode) ID() string {
|
2023-04-08 13:58:47 -06:00
|
|
|
return node.id
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a new listener channel for the node, add it to the nodes listener list, and return the new channel
|
2023-06-03 21:27:20 -06:00
|
|
|
const listener_buffer = 1000
|
2023-06-01 22:42:47 -06:00
|
|
|
func (node * BaseNode) UpdateChannel() chan GraphSignal {
|
|
|
|
new_listener := make(chan GraphSignal, listener_buffer)
|
|
|
|
node.RegisterChannel(new_listener)
|
2023-04-08 13:58:47 -06:00
|
|
|
return new_listener
|
|
|
|
}
|
|
|
|
|
2023-06-01 22:42:47 -06:00
|
|
|
func (node * BaseNode) RegisterChannel(listener chan GraphSignal) {
|
2023-04-08 13:58:47 -06:00
|
|
|
node.listeners_lock.Lock()
|
2023-06-01 22:42:47 -06:00
|
|
|
_, exists := node.listeners[listener]
|
|
|
|
if exists == false {
|
|
|
|
node.listeners[listener] = listener
|
2023-04-08 13:58:47 -06:00
|
|
|
}
|
2023-06-01 22:42:47 -06:00
|
|
|
node.listeners_lock.Unlock()
|
|
|
|
}
|
2023-04-08 13:58:47 -06:00
|
|
|
|
2023-06-01 22:42:47 -06:00
|
|
|
func (node * BaseNode) UnregisterChannel(listener chan GraphSignal) {
|
|
|
|
node.listeners_lock.Lock()
|
|
|
|
_, exists := node.listeners[listener]
|
|
|
|
if exists == false {
|
|
|
|
panic("Attempting to unregister non-registered listener")
|
|
|
|
} else {
|
|
|
|
delete(node.listeners, listener)
|
2023-04-08 13:58:47 -06:00
|
|
|
}
|
|
|
|
node.listeners_lock.Unlock()
|
2023-06-01 22:42:47 -06:00
|
|
|
}
|
2023-04-08 13:58:47 -06:00
|
|
|
|
2023-06-01 22:42:47 -06:00
|
|
|
// Send the update to listener channels
|
|
|
|
func (node * BaseNode) UpdateListeners(update GraphSignal) {
|
|
|
|
node.listeners_lock.Lock()
|
|
|
|
|
2023-06-02 17:31:29 -06:00
|
|
|
closed := []chan GraphSignal{}
|
|
|
|
|
2023-06-01 22:42:47 -06:00
|
|
|
for _, listener := range node.listeners {
|
2023-06-20 16:35:16 -06:00
|
|
|
Log.Logf("listeners", "UPDATE_LISTENER %s: %p", node.Name(), listener)
|
2023-06-02 17:31:29 -06:00
|
|
|
select {
|
|
|
|
case listener <- update:
|
|
|
|
default:
|
2023-06-20 16:35:16 -06:00
|
|
|
Log.Logf("listeners", "CLOSED_LISTENER: %s: %p", node.Name(), listener)
|
2023-06-03 21:27:20 -06:00
|
|
|
go func(node GraphNode, listener chan GraphSignal) {
|
|
|
|
listener <- NewSignal(node, "listener_closed")
|
|
|
|
close(listener)
|
|
|
|
}(node, listener)
|
2023-06-02 17:31:29 -06:00
|
|
|
closed = append(closed, listener)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, listener := range(closed) {
|
|
|
|
delete(node.listeners, listener)
|
2023-06-01 22:42:47 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
node.listeners_lock.Unlock()
|
2023-04-08 13:58:47 -06:00
|
|
|
}
|
|
|
|
|
2023-06-18 19:14:07 -06:00
|
|
|
func (node * BaseNode) PropagateUpdate(signal GraphSignal) {
|
2023-06-02 17:31:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func SendUpdate(node GraphNode, signal GraphSignal) {
|
2023-06-04 17:23:49 -06:00
|
|
|
node_name := "nil"
|
|
|
|
if node != nil {
|
|
|
|
node_name = node.Name()
|
2023-06-03 01:38:35 -06:00
|
|
|
}
|
2023-06-20 16:35:16 -06:00
|
|
|
Log.Logf("update", "UPDATE %s <- %s: %+v", node_name, signal.Source(), signal)
|
2023-06-01 22:42:47 -06:00
|
|
|
node.UpdateListeners(signal)
|
2023-06-18 19:14:07 -06:00
|
|
|
node.PropagateUpdate(signal)
|
2023-04-08 13:58:47 -06:00
|
|
|
}
|
2023-06-02 17:31:29 -06:00
|
|
|
|