From 96c2b84b6f7434f298e959dad9f047585992c9ee Mon Sep 17 00:00:00 2001 From: Noah Metz Date: Sun, 30 Jul 2023 10:09:04 -0600 Subject: [PATCH] * --- gql.go | 20 +++++--- lockable.go | 131 +++++++++++++++++++++-------------------------- lockable_test.go | 28 +++++----- node.go | 7 ++- signal.go | 16 +++--- 5 files changed, 94 insertions(+), 108 deletions(-) diff --git a/gql.go b/gql.go index fd3d144..e7607f9 100644 --- a/gql.go +++ b/gql.go @@ -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 }, diff --git a/lockable.go b/lockable.go index 1dc063e..e000bce 100644 --- a/lockable.go +++ b/lockable.go @@ -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: diff --git a/lockable_test.go b/lockable_test.go index 5d5b422..988429c 100644 --- a/lockable_test.go +++ b/lockable_test.go @@ -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) diff --git a/node.go b/node.go index 1c046e6..3bc47ca 100644 --- a/node.go +++ b/node.go @@ -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) } diff --git a/signal.go b/signal.go index 72e91c3..95adab9 100644 --- a/signal.go +++ b/signal.go @@ -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 {