gql_cataclysm
noah metz 2023-07-30 10:09:04 -06:00
parent 79e40bf3f3
commit 96c2b84b6f
5 changed files with 94 additions and 108 deletions

@ -844,16 +844,18 @@ func NewGQLExtContext() *GQLExtContext {
"requirements",
LockableExtType,
func(p graphql.ResolveParams, val interface{}) ([]NodeID, error) {
id_strs, ok := val.(map[NodeID]ReqState)
id_strs, ok := val.(LinkMap)
if ok == false {
return nil, fmt.Errorf("can't parse requirements %+v as string, %s", val, reflect.TypeOf(val))
}
ids := make([]NodeID, len(id_strs))
i := 0
for id, _ := range(id_strs) {
ids[i] = id
i++
for id, state := range(id_strs) {
if state.Link == "linked" {
ids[i] = id
i++
}
}
return ids, nil
},
@ -862,16 +864,18 @@ func NewGQLExtContext() *GQLExtContext {
"dependencies",
LockableExtType,
func(p graphql.ResolveParams, val interface{}) ([]NodeID, error) {
id_strs, ok := val.(map[NodeID]string)
id_strs, ok := val.(LinkMap)
if ok == false {
return nil, fmt.Errorf("can't parse dependencies %+v as string, %s", val, reflect.TypeOf(val))
}
ids := make([]NodeID, len(id_strs))
i := 0
for id, _ := range(id_strs) {
ids[i] = id
i++
for id, state := range(id_strs) {
if state.Link == "linked" {
ids[i] = id
i++
}
}
return ids, nil
},

@ -56,24 +56,46 @@ func (ext *ListenerExt) Process(ctx *Context, princ_id NodeID, node *Node, signa
}
// ReqState holds the multiple states of a requirement
type ReqState struct {
type LinkState struct {
Link string `json:"link"`
Lock string `json:"lock"`
Initiator NodeID `json:"initiator"`
}
// A LockableExt allows a node to be linked to other nodes(via LinkSignal) and locked/unlocked(via LockSignal)
type LockableExt struct {
Owner *NodeID
PendingOwner *NodeID
Requirements map[NodeID]ReqState
Dependencies map[NodeID]string
type LinkMap map[NodeID]LinkState
func (m LinkMap) MarshalJSON() ([]byte, error) {
tmp := map[string]LinkState{}
for id, state := range(m) {
tmp[id.String()] = state
}
return json.Marshal(tmp)
}
func (m LinkMap) UnmarshalJSON(data []byte) error {
tmp := map[string]LinkState{}
err := json.Unmarshal(data, &tmp)
if err != nil {
return err
}
for id_str, state := range(tmp) {
id, err := ParseID(id_str)
if err != nil {
return err
}
m[id] = state
}
return nil
}
type LockableExtJSON struct {
type LockableExt struct {
Owner *NodeID `json:"owner"`
PendingOwner *NodeID `json:"pending_owner"`
Requirements map[string]ReqState `json:"requirements"`
Dependencies map[string]string `json:"dependencies"`
Requirements LinkMap `json:"requirements"`
Dependencies LinkMap `json:"dependencies"`
}
func (ext *LockableExt) Field(name string) interface{} {
@ -94,28 +116,13 @@ func (ext *LockableExt) Field(name string) interface{} {
}
func LoadLockableExt(ctx *Context, data []byte) (Extension, error) {
var j LockableExtJSON
err := json.Unmarshal(data, &j)
if err != nil {
return nil, err
}
requirements, err := LoadIDMap(j.Requirements)
if err != nil {
return nil, err
}
dependencies, err := LoadIDMap(j.Dependencies)
var ext LockableExt
err := json.Unmarshal(data, &ext)
if err != nil {
return nil, err
}
return &LockableExt{
Owner: j.Owner,
PendingOwner: j.PendingOwner,
Requirements: requirements,
Dependencies: dependencies,
}, nil
return &ext, nil
}
func (ext *ListenerExt) Serialize() ([]byte, error) {
@ -127,20 +134,15 @@ func (ext *LockableExt) Type() ExtType {
}
func (ext *LockableExt) Serialize() ([]byte, error) {
return json.MarshalIndent(&LockableExtJSON{
Owner: ext.Owner,
PendingOwner: ext.PendingOwner,
Requirements: IDMap(ext.Requirements),
Dependencies: IDMap(ext.Dependencies),
}, "", " ")
return json.MarshalIndent(ext, "", " ")
}
func NewLockableExt() *LockableExt {
return &LockableExt{
Owner: nil,
PendingOwner: nil,
Requirements: map[NodeID]ReqState{},
Dependencies: map[NodeID]string{},
Requirements: map[NodeID]LinkState{},
Dependencies: map[NodeID]LinkState{},
}
}
@ -315,9 +317,9 @@ func (ext *LockableExt) HandleLockSignal(ctx *Context, source NodeID, node *Node
}
}
func (ext *LockableExt) HandleLinkStartSignal(ctx *Context, source NodeID, node *Node, signal LinkStartSignal) {
func (ext *LockableExt) HandleLinkStartSignal(ctx *Context, source NodeID, node *Node, signal IDStateSignal) {
ctx.Log.Logf("lockable", "LINK__START_SIGNAL: %s->%s %+v", source, node.ID, signal)
link_type := signal.LinkType
link_type := signal.State
target := signal.ID
switch link_type {
case "req":
@ -340,8 +342,8 @@ func (ext *LockableExt) HandleLinkStartSignal(ctx *Context, source NodeID, node
} else if dep_exists == true {
ctx.Send(node.ID, source, NewLinkStartSignal("already_dep", target))
} else {
ext.Requirements[target] = ReqState{"linking", "unlocked"}
ctx.Send(node.ID, target, NewLinkSignal("link_as_req"))
ext.Requirements[target] = LinkState{"linking", "unlocked", source}
ctx.Send(node.ID, target, NewLinkSignal("linked_as_req"))
ctx.Send(node.ID, source, NewLinkStartSignal("linking_req", target))
}
}
@ -353,14 +355,14 @@ func (ext *LockableExt) HandleLinkSignal(ctx *Context, source NodeID, node *Node
ctx.Log.Logf("lockable", "LINK_SIGNAL: %s->%s %+v", source, node.ID, signal)
state := signal.State
switch state {
case "link_as_dep":
case "linked_as_dep":
state, exists := ext.Requirements[source]
if exists == true && state.Link == "linked" {
ctx.Send(node.ID, source, NewLinkSignal("already_req"))
ctx.Send(node.ID, state.Initiator, NewLinkStartSignal("linked_as_req", source))
} else if state.Link == "linking" {
state.Link = "linked"
ext.Requirements[source] = state
ctx.Send(node.ID, source, NewLinkSignal("linked_as_dep"))
ctx.Send(node.ID, source, NewLinkSignal("linked_as_req"))
} else if ext.PendingOwner != ext.Owner {
if ext.Owner == nil {
ctx.Send(node.ID, source, NewLinkSignal("locking"))
@ -368,17 +370,19 @@ func (ext *LockableExt) HandleLinkSignal(ctx *Context, source NodeID, node *Node
ctx.Send(node.ID, source, NewLinkSignal("unlocking"))
}
} else {
ext.Requirements[source] = ReqState{"linking", "unlocked"}
ctx.Send(node.ID, source, NewLinkSignal("link_as_req"))
ext.Requirements[source] = LinkState{"linking", "unlocked", source}
ctx.Send(node.ID, source, NewLinkSignal("linked_as_req"))
}
ctx.Log.Logf("lockable", "%s is a dependency of %s", node.ID, source)
case "link_as_req":
case "linked_as_req":
state, exists := ext.Dependencies[source]
if exists == true && state == "linked" {
ctx.Send(node.ID, source, NewLinkSignal("already_dep"))
} else if state == "linking" {
ext.Dependencies[source] = "linked"
ctx.Send(node.ID, source, NewLinkSignal("linked_as_req"))
if exists == true && state.Link == "linked" {
ctx.Send(node.ID, state.Initiator, NewLinkStartSignal("linked_as_dep", source))
} else if state.Link == "linking" {
state.Link = "linked"
ext.Dependencies[source] = state
ctx.Send(node.ID, source, NewLinkSignal("linked_as_dep"))
} else if ext.PendingOwner != ext.Owner {
if ext.Owner == nil {
ctx.Send(node.ID, source, NewLinkSignal("locking"))
@ -386,28 +390,7 @@ func (ext *LockableExt) HandleLinkSignal(ctx *Context, source NodeID, node *Node
ctx.Send(node.ID, source, NewLinkSignal("unlocking"))
}
} else {
ext.Dependencies[source] = "linking"
ctx.Send(node.ID, source, NewLinkSignal("link_as_dep"))
}
case "linked_as_dep":
state, exists := ext.Dependencies[source]
if exists == false {
ctx.Send(node.ID, source, NewLinkSignal("not_linking"))
} else if state == "linked" {
} else if state == "linking" {
ext.Dependencies[source] = "linked"
ctx.Send(node.ID, source, NewLinkSignal("linked_as_req"))
}
ctx.Log.Logf("lockable", "%s is a dependency of %s", node.ID, source)
case "linked_as_req":
state, exists := ext.Requirements[source]
if exists == false {
ctx.Send(node.ID, source, NewLinkSignal("not_linking"))
} else if state.Link == "linked" {
} else if state.Link == "linking" {
state.Link = "linked"
ext.Requirements[source] = state
ext.Dependencies[source] = LinkState{"linking", "unlocked", source}
ctx.Send(node.ID, source, NewLinkSignal("linked_as_dep"))
}
ctx.Log.Logf("lockable", "%s is a requirement of %s", node.ID, source)
@ -424,7 +407,7 @@ func (ext *LockableExt) Process(ctx *Context, source NodeID, node *Node, signal
case Up:
owner_sent := false
for dependency, state := range(ext.Dependencies) {
if state == "linked" {
if state.Link == "linked" {
err := ctx.Send(node.ID, dependency, signal)
if err != nil {
ctx.Log.Logf("signal", "LOCKABLE_SIGNAL_ERR: %s->%s - %e", node.ID, dependency, err)
@ -462,7 +445,7 @@ func (ext *LockableExt) Process(ctx *Context, source NodeID, node *Node, signal
case LockSignalType:
ext.HandleLockSignal(ctx, source, node, signal.(StateSignal))
case LinkStartSignalType:
ext.HandleLinkStartSignal(ctx, source, node, signal.(LinkStartSignal))
ext.HandleLinkStartSignal(ctx, source, node, signal.(IDStateSignal))
default:
}
default:

@ -21,7 +21,7 @@ var link_policy = NewAllNodesPolicy(Actions{MakeAction(LinkSignalType, "*"), Mak
var lock_policy = NewAllNodesPolicy(Actions{MakeAction(LockSignalType, "*")})
func TestLink(t *testing.T) {
ctx := lockableTestContext(t, []string{})
ctx := lockableTestContext(t, []string{"lockable"})
l1_listener := NewListenerExt(10)
l1 := NewNode(ctx, nil, TestLockableType, 10, nil,
@ -40,14 +40,10 @@ func TestLink(t *testing.T) {
err := LinkRequirement(ctx, l1.ID, l2.ID)
fatalErr(t, err)
_, err = WaitForSignal(ctx, l1_listener, time.Millisecond*10, LinkSignalType, func(sig StateSignal) bool {
_, err = WaitForSignal(ctx, l1_listener, time.Millisecond*10, LinkStartSignalType, func(sig IDStateSignal) bool {
return sig.State == "linked_as_req"
})
fatalErr(t, err)
_, err = WaitForSignal(ctx, l2_listener, time.Millisecond*10, LinkSignalType, func(sig StateSignal) bool {
return sig.State == "linked_as_dep"
})
fatalErr(t, err)
err = ctx.Send(l2.ID, l2.ID, NewStatusSignal("TEST", l2.ID))
fatalErr(t, err)
@ -95,7 +91,7 @@ func TestLink10K(t *testing.T) {
for range(lockables) {
_, err := WaitForSignal(ctx, l0_listener, time.Millisecond*10, LinkSignalType, func(sig StateSignal) bool {
_, err := WaitForSignal(ctx, l0_listener, time.Millisecond*10, LinkStartSignalType, func(sig IDStateSignal) bool {
return sig.State == "linked_as_req"
})
fatalErr(t, err)
@ -144,7 +140,7 @@ func TestLock(t *testing.T) {
err = LinkRequirement(ctx, l0.ID, l5.ID)
fatalErr(t, err)
linked_as_req := func(sig StateSignal) bool {
linked_as_req := func(sig IDStateSignal) bool {
return sig.State == "linked_as_req"
}
@ -152,22 +148,22 @@ func TestLock(t *testing.T) {
return sig.State == "locked"
}
_, err = WaitForSignal(ctx, l1_listener, time.Millisecond*10, LinkSignalType, linked_as_req)
_, err = WaitForSignal(ctx, l1_listener, time.Millisecond*10, LinkStartSignalType, linked_as_req)
fatalErr(t, err)
_, err = WaitForSignal(ctx, l1_listener, time.Millisecond*10, LinkSignalType, linked_as_req)
_, err = WaitForSignal(ctx, l1_listener, time.Millisecond*10, LinkStartSignalType, linked_as_req)
fatalErr(t, err)
_, err = WaitForSignal(ctx, l1_listener, time.Millisecond*10, LinkSignalType, linked_as_req)
_, err = WaitForSignal(ctx, l1_listener, time.Millisecond*10, LinkStartSignalType, linked_as_req)
fatalErr(t, err)
_, err = WaitForSignal(ctx, l1_listener, time.Millisecond*10, LinkSignalType, linked_as_req)
_, err = WaitForSignal(ctx, l1_listener, time.Millisecond*10, LinkStartSignalType, linked_as_req)
fatalErr(t, err)
_, err = WaitForSignal(ctx, l0_listener, time.Millisecond*10, LinkSignalType, linked_as_req)
_, err = WaitForSignal(ctx, l0_listener, time.Millisecond*10, LinkStartSignalType, linked_as_req)
fatalErr(t, err)
_, err = WaitForSignal(ctx, l0_listener, time.Millisecond*10, LinkSignalType, linked_as_req)
_, err = WaitForSignal(ctx, l0_listener, time.Millisecond*10, LinkStartSignalType, linked_as_req)
fatalErr(t, err)
_, err = WaitForSignal(ctx, l0_listener, time.Millisecond*10, LinkSignalType, linked_as_req)
_, err = WaitForSignal(ctx, l0_listener, time.Millisecond*10, LinkStartSignalType, linked_as_req)
fatalErr(t, err)
_, err = WaitForSignal(ctx, l0_listener, time.Millisecond*10, LinkSignalType, linked_as_req)
_, err = WaitForSignal(ctx, l0_listener, time.Millisecond*10, LinkStartSignalType, linked_as_req)
fatalErr(t, err)
err = LockLockable(ctx, l1)

@ -33,8 +33,11 @@ var (
// A NodeID uniquely identifies a Node
type NodeID uuid.UUID
func (id NodeID) MarshalJSON() ([]byte, error) {
str := id.String()
func (id *NodeID) MarshalJSON() ([]byte, error) {
str := ""
if id != nil {
str = id.String()
}
return json.Marshal(&str)
}

@ -189,16 +189,16 @@ func NewLinkSignal(state string) StateSignal {
}
}
type LinkStartSignal struct {
IDSignal
LinkType string `json:"link_type"`
func NewIDStateSignal(signal_type SignalType, direction SignalDirection, state string, id NodeID) IDStateSignal {
return IDStateSignal{
BaseSignal: NewBaseSignal(signal_type, direction),
ID: id,
State: state,
}
}
func NewLinkStartSignal(link_type string, target NodeID) LinkStartSignal {
return LinkStartSignal{
IDSignal: NewIDSignal(LinkStartSignalType, Direct, target),
LinkType: link_type,
}
func NewLinkStartSignal(link_type string, target NodeID) IDStateSignal {
return NewIDStateSignal(LinkStartSignalType, Direct, link_type, target)
}
func NewLockSignal(state string) StateSignal {