From 279ea758ea7f6cf5e5ad6828573581a43ca11e4a Mon Sep 17 00:00:00 2001 From: StefansArya Date: Wed, 7 Sep 2022 14:01:11 +0700 Subject: [PATCH 01/15] Commit current adaptation progress --- blackprint/blackprint.go | 3 + blackprint/nodesBPFunction.go | 5 + blackprint/nodesBPVariable.go | 321 +++++++++++++++++++++++++++++++++ blackprint/nodesEnvironment.go | 134 ++++++++++++++ blackprint/nodesFnPortVar.go | 5 + engine/bpVar.go | 43 +++++ engine/cable.go | 143 +++++++++++++-- engine/customevent.go | 32 ++-- engine/engine.go | 61 +++++-- engine/enums.go | 8 + engine/environment.go | 52 ++++++ engine/interface.go | 196 ++++++++++++-------- engine/node.go | 137 ++++++++++++-- engine/nodes/enums.go | 13 ++ engine/port.go | 52 ++++-- engine/portFeature.go | 97 ++++++++++ engine/portGhost.go | 19 ++ engine/references.go | 8 + engine/routePort.go | 115 ++++++++++++ example/button.go | 2 +- example/example_test.go | 9 +- example/input.go | 8 +- example/logger.go | 2 +- example/math.go | 10 +- go.mod | 4 +- go.sum | 6 + internal/cmd/root.go | 2 +- types/types.go | 1 + utils/utils.go | 32 ++++ 29 files changed, 1351 insertions(+), 169 deletions(-) create mode 100644 blackprint/nodesBPFunction.go create mode 100644 blackprint/nodesBPVariable.go create mode 100644 blackprint/nodesEnvironment.go create mode 100644 blackprint/nodesFnPortVar.go create mode 100644 engine/bpVar.go create mode 100644 engine/enums.go create mode 100644 engine/environment.go create mode 100644 engine/nodes/enums.go create mode 100644 engine/portFeature.go create mode 100644 engine/portGhost.go create mode 100644 engine/references.go create mode 100644 engine/routePort.go diff --git a/blackprint/blackprint.go b/blackprint/blackprint.go index 90a1535..8e67618 100644 --- a/blackprint/blackprint.go +++ b/blackprint/blackprint.go @@ -19,3 +19,6 @@ func RegisterInterface(namespace string, constructor func(any) any) { engine.QInterfaceList[namespace] = constructor } + +var Event = engine.Event +var Environment = engine.QEnvironment diff --git a/blackprint/nodesBPFunction.go b/blackprint/nodesBPFunction.go new file mode 100644 index 0000000..7f4119a --- /dev/null +++ b/blackprint/nodesBPFunction.go @@ -0,0 +1,5 @@ +package blackprint + +func registerBpFuncNode() { + +} diff --git a/blackprint/nodesBPVariable.go b/blackprint/nodesBPVariable.go new file mode 100644 index 0000000..8a9bd68 --- /dev/null +++ b/blackprint/nodesBPVariable.go @@ -0,0 +1,321 @@ +package blackprint + +import ( + "reflect" + "strconv" + + "github.com/blackprint/engine-go/engine" + "github.com/blackprint/engine-go/engine/nodes" + "github.com/blackprint/engine-go/port" + "github.com/blackprint/engine-go/types" + "github.com/blackprint/engine-go/utils" +) + +type bpVarSet struct { + *engine.Node +} +type bpVarGet struct { + *engine.Node +} + +func (b *bpVarSet) Update(c *engine.Cable) { + b.Iface.QBpVarRef.Value.Set(b.Input["Val"].Get()) +} + +type bpVarGetSet struct { + *engine.Interface + QOnChanged func(*engine.Port) +} + +func (b *bpVarGetSet) Imported(data map[string]any) { + if _, exist := data["scope"]; exist { + panic("'scope' options is required for creating variable node") + } + + if _, exist := data["name"]; exist { + panic("'name' options is required for creating variable node") + } + + b.ChangeVar(data["name"].(string), data["scope"].(int)) + b.QBpVarRef.Used = append(b.QBpVarRef.Used, b) +} + +func (b *bpVarGetSet) ChangeVar(name string, scopeId int) map[string]*engine.BPVariable { + if _, exist := b.Data["name"]; exist { + panic("Can't change variable node that already be initialized") + } + + b.Data["name"] = &engine.GetterSetter{Value: name} + b.Data["scope"] = &engine.GetterSetter{Value: scopeId} + + thisInstance := utils.GetProperty(b.Node, "Instance").(*engine.Instance) + funcInstance := thisInstance.QFuncMain + if funcInstance == nil { + funcInstance.Node.QFuncInstance + } + + var scope map[string]*engine.BPVariable + if scopeId == engine.VarScopePublic { + if funcInstance != nil { + scope := funcInstance.Node.RootInstance.Variables + } else { + scope := thisInstance.Variables + } + } else if scopeId == engine.VarScopeShared { + scope := funcInstance.Variables + } else { // private + scope := thisInstance.Variables + } + + if _, exist := scope[name]; !exist { + var scopeName string + if scopeId == engine.VarScopePublic { + scopeName = "public" + } else if scopeId == engine.VarScopePrivate { + scopeName = "private" + } else if scopeId == engine.VarScopeShared { + scopeName = "shared" + } else { + scopeName = "unknown" + } + + panic("'" + name + "' variable was not defined on the '" + scopeName + " (scopeId: " + strconv.Itoa(scopeId) + ")' instance") + } + + return scope +} + +func (b *bpVarGetSet) UseType(port *engine.Port) bool { + if b.QBpVarRef.Type != 0 { // Type was set + if port == nil { + b.QBpVarRef.Type = 0 // Type not set + } + return true + } + + if port == nil { + panic("Can't set type with null") + } + + return false +} + +func (b *bpVarGetSet) UseType_(port *engine.Port, targetPort *engine.Port) { + b.QBpVarRef.Type = port.Type + targetPort.ConnectPort(port) + + // Also create port for other node that using $this variable + for _, item := range b.QBpVarRef.Used { + utils.CallFunction(item, "QReinitPort", nil) + } +} + +func (b *bpVarGetSet) Destroy() { + temp := b.QBpVarRef + if temp == nil { + return + } + + utils.RemoveItem(temp.Used, b.Interface) + + listener := b.QBpVarRef.Listener + if listener == nil { + return + } + + utils.RemoveItem(listener, b.Interface) +} + +type iVarSet struct { + *bpVarGetSet + QEventListen string +} + +func (b *iVarSet) UseType(port *engine.Port) { + if !b.bpVarGetSet.UseType(port) { + b.bpVarGetSet.UseType_(port, b.QReinitPort()) + } +} + +func (b *iVarSet) ChangeVar(name string, scopeId int) { + if _, exist := b.Data["name"]; exist { + panic("Can't change variable node that already be initialized") + } + + if b.QOnChanged != nil && b.QBpVarRef != nil { + b.QBpVarRef.Off("value", b.QOnChanged) + } + + scope := b.bpVarGetSet.ChangeVar(name, scopeId) + b.Title = "Get " + name + + temp := scope[b.Data["name"].Get().(string)] + b.QBpVarRef = temp + if temp.Type == 0 { // Type not set + return + } + + b.QReinitPort() +} + +func (b *iVarSet) QReinitPort() *engine.Port { + temp := b.QBpVarRef + node := b.Node + + if b.Output["Val"] != nil { + utils.CallFunction(node, "DeletePort", &[]reflect.Value{ + reflect.ValueOf("Val"), + }) + } + + ref := utils.GetProperty(b.Node, "Output").(map[string]*engine.PortOutputGetterSetter) + utils.CallFunction(b.Node, "CreatePort", &[]reflect.Value{ + reflect.ValueOf("Val"), + reflect.ValueOf(temp.Type), + }) + + if temp.Type == types.Function { + b.QEventListen = "call" + b.QOnChanged = func(p *engine.Port) { + ref["Val"].Call() + } + } else { + b.QEventListen = "value" + b.QOnChanged = func(p *engine.Port) { + ref["Val"].Set(temp.Value.Get()) + } + } + + temp.On(b.QEventListen, b.QOnChanged) + return b.Output["Val"] +} + +func (b *iVarSet) Destroy() { + if b.QEventListen != "" { + b.QBpVarRef.Off(b.QEventListen, b.QOnChanged) + } + + b.bpVarGetSet.Destroy() +} + +type iVarGet struct { + *bpVarGetSet +} + +func (b *iVarGet) UseType(port *engine.Port) { + if !b.bpVarGetSet.UseType(port) { + b.bpVarGetSet.UseType_(port, b.QReinitPort()) + } +} + +func (b *iVarGet) ChangeVar(name string, scopeId int) { + scope := b.bpVarGetSet.ChangeVar(name, scopeId) + b.Title = "Set " + name + + temp := scope[b.Data["name"].Get().(string)] + b.QBpVarRef = temp + if temp.Type == 0 { // Type not set + return + } + + b.QReinitPort() +} + +func (b *iVarGet) QReinitPort() *engine.Port { + input := b.Input + node := b.Node + temp := b.QBpVarRef + + if _, exist := input["Val"]; exist { + utils.CallFunction(node, "DeletePort", &[]reflect.Value{ + reflect.ValueOf("Input"), + reflect.ValueOf("Val"), + }) + } + + if temp.Type == types.Function { + utils.CallFunction(node, "CreatePort", &[]reflect.Value{ + reflect.ValueOf("Input"), + reflect.ValueOf("Val"), + reflect.ValueOf(port.Trigger(func(p *engine.Port) { + temp.Emit("call", nil) + })), + }) + } else { + utils.CallFunction(node, "CreatePort", &[]reflect.Value{ + reflect.ValueOf("Input"), + reflect.ValueOf("Val"), + reflect.ValueOf(temp.Type), + }) + } + + return b.Input["Val"] +} + +func registerBPVarNode() { + RegisterNode("BP/Var/Set", func(i *engine.Instance) any { + node := &bpVarSet{ + Node: &engine.Node{ + Instance: i, + }, + } + + iface := node.SetInterface("BPIC/BP/Var/Set").(*iVarSet) + + // Specify data field from here to make it enumerable and exportable + iface.Data = engine.InterfaceData{ + "name": &engine.GetterSetter{Value: ""}, + "scope": &engine.GetterSetter{Value: engine.VarScopePublic}, + } + + iface.Title = "VarSet" + iface.Type = "bp-var-set" + iface.QEnum = nodes.BPVarSet + iface.QDynamicPort = true + + return node + }) + + RegisterInterface("BPIC/BP/Var/Get", func(node any) any { + return &iVarGet{ + bpVarGetSet: &bpVarGetSet{ + Interface: &engine.Interface{ + Node: node, + }, + }, + } + }) + + RegisterNode("BP/Var/Get", func(i *engine.Instance) any { + node := &bpVarGet{ + Node: &engine.Node{ + Instance: i, + }, + } + + iface := node.SetInterface("BPIC/BP/Var/Get").(*iVarGet) + + // Specify data field from here to make it enumerable and exportable + iface.Data = engine.InterfaceData{ + "name": &engine.GetterSetter{Value: ""}, + "scope": &engine.GetterSetter{Value: engine.VarScopePublic}, + } + + iface.Title = "VarGet" + iface.Type = "bp-var-get" + iface.QEnum = nodes.BPVarGet + iface.QDynamicPort = true + + return node + }) + + RegisterInterface("BPIC/BP/Var/Get", func(node any) any { + return &iVarGet{ + bpVarGetSet: &bpVarGetSet{ + Interface: &engine.Interface{ + Node: node, + }, + }, + } + }) +} diff --git a/blackprint/nodesEnvironment.go b/blackprint/nodesEnvironment.go new file mode 100644 index 0000000..b6ab169 --- /dev/null +++ b/blackprint/nodesEnvironment.go @@ -0,0 +1,134 @@ +package blackprint + +import ( + "github.com/blackprint/engine-go/engine" + "github.com/blackprint/engine-go/engine/nodes" +) + +type bpEnvGet struct { + *engine.Node + Iface *engine.Interface +} + +type bpEnvSet struct { + *engine.Node + Iface *engine.Interface +} + +func (b *bpEnvSet) Update(c *engine.Cable) { + Environment.Set(b.Iface.Data["name"].Get().(string), c.GetValue().(string)) +} + +type bpEnvGetSet struct { + *engine.Interface +} + +func (b *bpEnvGetSet) Imported(data map[string]any) { + if data["name"] == nil { + panic("Parameter 'name' is required") + } + + b.Data["name"].Set(data["name"]) + name := data["name"].(string) + + if _, exists := Environment.Map[name]; !exists { + Environment.Set(name, "") + } +} + +type iEnvGet struct { + *bpEnvGetSet + QListener func(any) +} + +func (b *iEnvGet) Imported(data map[string]any) { + b.Imported(data) + + b.QListener = func(v any) { + ev := v.(*engine.EnvironmentEvent) + if ev.Key != b.Data["name"].Get().(string) { + return + } + + b.Ref.Output["Val"].Set(ev.Value) + } + + Event.On("environment.changed environment.added", b.QListener) + b.Ref.Output["Val"].Set(Environment.Map[b.Data["name"].Get().(string)]) +} + +func (b *iEnvGet) Destroy() { + if b.QListener == nil { + return + } + + Event.Off("environment.changed environment.added", b.QListener) +} + +type iEnvSet struct { + *bpEnvGetSet +} + +func registerEnvNode() { + RegisterNode("BP/Env/Get", func(i *engine.Instance) any { + node := &bpEnvGet{ + Node: &engine.Node{ + Instance: i, + }, + } + + iface := node.SetInterface("BPIC/BP/Env/Get").(*iEnvGet) + + // Specify data field from here to make it enumerable and exportable + iface.Data = engine.InterfaceData{ + "name": &engine.GetterSetter{Value: ""}, + } + + iface.Title = "EnvGet" + iface.Type = "bp-env-get" + iface.QEnum = nodes.BPEnvGet + + return node + }) + + RegisterInterface("BPIC/BP/Env/Get", func(node any) any { + return &iEnvGet{ + bpEnvGetSet: &bpEnvGetSet{ + Interface: &engine.Interface{ + Node: node, + }, + }, + } + }) + + RegisterNode("BP/Env/Set", func(i *engine.Instance) any { + node := &bpEnvSet{ + Node: &engine.Node{ + Instance: i, + }, + } + + iface := node.SetInterface("BPIC/BP/Env/Set").(*iEnvSet) + + // Specify data field from here to make it enumerable and exportable + iface.Data = engine.InterfaceData{ + "name": &engine.GetterSetter{Value: ""}, + } + + iface.Title = "EnvSet" + iface.Type = "bp-env-set" + iface.QEnum = nodes.BPEnvSet + + return node + }) + + RegisterInterface("BPIC/BP/Env/Set", func(node any) any { + return &iEnvSet{ + bpEnvGetSet: &bpEnvGetSet{ + Interface: &engine.Interface{ + Node: node, + }, + }, + } + }) +} diff --git a/blackprint/nodesFnPortVar.go b/blackprint/nodesFnPortVar.go new file mode 100644 index 0000000..aede51b --- /dev/null +++ b/blackprint/nodesFnPortVar.go @@ -0,0 +1,5 @@ +package blackprint + +func registerBpPortVarNode() { + +} diff --git a/engine/bpVar.go b/engine/bpVar.go new file mode 100644 index 0000000..2020cf5 --- /dev/null +++ b/engine/bpVar.go @@ -0,0 +1,43 @@ +package engine + +import ( + "reflect" + + "github.com/blackprint/engine-go/utils" +) + +type bpVarValue struct { + *CustomEvent + val any +} + +func (b *bpVarValue) Get() any { + return b.val +} + +func (b *bpVarValue) Set(val any) { + b.val = val + b.Emit("Value", nil) +} + +// used for instance.CreateVariable +type BPVariable struct { + *CustomEvent + Id string + Title string + Type reflect.Kind + Used []*Interface + Value bpVarValue + Listener []*Interface +} + +func (b *BPVariable) Destroy() { + for _, iface := range b.Used { + ins := utils.GetProperty((utils.GetProperty(iface, "Node")), "Instance").(*Instance) + utils.CallFunction(ins, "DeleteNode", &[]reflect.Value{ + reflect.ValueOf(iface), + }) + } + + b.Used = b.Used[:0] +} diff --git a/engine/cable.go b/engine/cable.go index 759b51c..124a8a1 100644 --- a/engine/cable.go +++ b/engine/cable.go @@ -2,12 +2,20 @@ package engine import ( "reflect" + + "github.com/blackprint/engine-go/utils" ) type Cable struct { - Type reflect.Kind - Owner *Port - Target *Port + Type reflect.Kind + Owner *Port + Target *Port + Input *Port + Output *Port + Disabled bool + IsRoute bool + Connected bool + QEvDisconnected bool } type CableEvent struct { @@ -16,42 +24,139 @@ type CableEvent struct { Target *Port } -func NewCable(owner *Port, target *Port) Cable { - return Cable{ +type PortSelfEvent struct { + Port *Port +} + +func NewCable(owner *Port, target *Port) *Cable { + var input *Port + var output *Port + + if owner.Source == PortInput { + input = owner + output = target + } else { + output = owner + input = target + } + + return &Cable{ Type: owner.Type, Owner: owner, Target: target, + Input: input, + Output: output, } } func (c *Cable) QConnected() { - c.Owner.QTrigger("cable.connect", CableEvent{ + c.Connected = true + + ownerEv := &CableEvent{ Cable: c, Port: c.Owner, Target: c.Target, - }) + } + c.Owner.Emit("cable.connect", ownerEv) + c.Owner.Iface.Emit("cable.connect", ownerEv) - c.Target.QTrigger("cable.connect", CableEvent{ + targetEv := &CableEvent{ Cable: c, Port: c.Target, Target: c.Owner, - }) + } + c.Target.Emit("cable.connect", targetEv) + c.Target.Iface.Emit("cable.connect", targetEv) - var inp, out *Port - if c.Owner.Source == PortInput { - inp = c.Owner - out = c.Target - } else { - inp = c.Target - out = c.Owner + if c.Output.Value == nil { + return } - if out.Value != nil { - inp.QTrigger("value", out) + inputEv := &PortSelfEvent{ + Port: c.Output, } + c.Input.Emit("value", inputEv) + c.Input.Iface.Emit("value", inputEv) + + utils.CallFunction(c.Input.Iface.Node, "Update", &[]reflect.Value{ + reflect.ValueOf(c), + }) } // For debugging func (c *Cable) String() string { - return "\nCable: " + c.Owner.Iface.Title + "." + c.Owner.Name + " <=> " + c.Target.Name + "." + c.Target.Iface.Title + return "\nCable: " + c.Output.Iface.Title + "." + c.Output.Name + " <=> " + c.Input.Name + "." + c.Input.Iface.Title +} + +func (c *Cable) GetValue() any { + return c.Output.Value +} + +func (c *Cable) Disconnect(which_ ...*Port) { // which = port + if c.IsRoute { // ToDo: simplify, use 'which' instead of check all + if c.Output.Cables != nil { + c.Output.Cables = c.Output.Cables[:0] + } else if c.Output.Out == c { + c.Output.Out = nil + } else if c.Input.Out == c { + c.Input.Out = nil + } + + c.Output.In = utils.RemoveItem[*Cable](c.Output.In, c) + c.Input.In = utils.RemoveItem[*Cable](c.Input.In, c) + + c.Connected = false + return + } + + hasWhich := len(which_) == 0 + which := which_[0] + alreadyEmitToInstance := false + + if c.Input != nil { + c.Input.QCache = nil + } + + if c.Owner != nil && (!hasWhich || which == c.Owner) { + utils.RemoveItem[*Cable](c.Owner.Cables, c) + + if c.Connected { + temp := &CableEvent{ + Cable: c, + Port: c.Owner, + Target: c.Target, + } + + c.Owner.Emit("disconnect", temp) + c.Owner.Iface.Emit("cable.disconnect", temp) + ins := utils.GetPropertyRef(c.Owner.Iface.Node, "Instance").(*Instance) + ins.Emit("cable.disconnect", temp) + + alreadyEmitToInstance = true + } else { + c.Owner.Iface.Emit("cable.cancel", &CableEvent{ + Cable: c, + Port: c.Owner, + Target: nil, + }) + } + } + + if c.Target != nil && c.Connected && (!hasWhich || which == c.Target) { + utils.RemoveItem[*Cable](c.Target.Cables, c) + + temp := &CableEvent{ + Cable: c, + Port: c.Target, + Target: c.Owner, + } + + c.Target.Emit("disconnect", temp) + c.Target.Iface.Emit("cable.disconnect", temp) + + if alreadyEmitToInstance == false { + ins := utils.GetPropertyRef(c.Target.Iface.Node, "Instance").(*Instance) + ins.Emit("cable.disconnect", temp) + } + } } diff --git a/engine/customevent.go b/engine/customevent.go index e5d4b73..3ddcbeb 100644 --- a/engine/customevent.go +++ b/engine/customevent.go @@ -2,6 +2,8 @@ package engine import ( "strings" + + "github.com/blackprint/engine-go/utils" ) type eventObj struct { @@ -9,16 +11,16 @@ type eventObj struct { once bool } -type customEvent struct { +type CustomEvent struct { events map[string][]*eventObj } -func (e *customEvent) listen(evName string, callback any, once bool) { +func (e *CustomEvent) listen(evName string, callback any, once bool) { if e.events == nil { e.events = map[string][]*eventObj{} } - evs := strings.Split(evName, ",") + evs := strings.Split(evName, " ") for _, name := range evs { list := e.events[name] @@ -33,7 +35,7 @@ func (e *customEvent) listen(evName string, callback any, once bool) { } if exist { - break + continue } e.events[name] = append(list, &eventObj{ @@ -43,43 +45,47 @@ func (e *customEvent) listen(evName string, callback any, once bool) { } } -func (e *customEvent) On(evName string, callback any) { +func (e *CustomEvent) On(evName string, callback any) { e.listen(evName, callback, false) } -func (e *customEvent) Once(evName string, callback any) { +func (e *CustomEvent) Once(evName string, callback any) { e.listen(evName, callback, true) } -func (e *customEvent) Off(evName string, callback any) { +func (e *CustomEvent) Off(evName string, callback any) { if e.events == nil { return } - evs := strings.Split(evName, ",") + evs := strings.Split(evName, " ") for _, name := range evs { if callback == nil { e.events[name] = []*eventObj{} - break + continue } list := e.events[name] + if list == nil { + continue + } + for i, cb := range list { if cb.callback == callback { - e.events[name] = append(list[:i], list[i+1:]...) - break + e.events[name] = utils.RemoveItemAtIndex(list, i) + continue } } } } -func (e *customEvent) QTrigger(evName string, data any) { +func (e *CustomEvent) Emit(evName string, data any) { list := e.events[evName] for i, cb := range list { cb.callback.(func(any))(data) if cb.once { - e.events[evName] = append(list[:i], list[i+1:]...) + e.events[evName] = utils.RemoveItemAtIndex(list, i) } } } diff --git a/engine/engine.go b/engine/engine.go index 470f07e..6196c9c 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -4,22 +4,27 @@ import ( "encoding/json" "fmt" "reflect" + "regexp" "github.com/blackprint/engine-go/utils" ) -type NodePort map[string]any +var Event = &CustomEvent{} + +type NodePortTemplate map[string]any type Instance struct { - IFace map[string]any // Storing with node id if exist - IFaceList map[int]any // Storing with node index + CustomEvent + Iface map[string]any // Storing with node id if exist + IfaceList map[int]any // Storing with node index settings map[string]bool + QFuncMain *bpFuncMain } func New() *Instance { return &Instance{ - IFace: map[string]any{}, - IFaceList: map[int]any{}, + Iface: map[string]any{}, + IfaceList: map[int]any{}, settings: map[string]bool{}, } } @@ -60,11 +65,23 @@ type nodePortTarget struct { Name string `json:"name"` } -type GetterSetter interface { +type getterSetter interface { Set(val any) Get() any } +type GetterSetter struct { + Value any +} + +func (b *GetterSetter) Get() any { + return b.Value +} + +func (b *GetterSetter) Set(Value any) { + b.Value = Value +} + func (instance *Instance) ImportJSON(str []byte) (err error) { var data SingleInstanceJSON @@ -73,7 +90,7 @@ func (instance *Instance) ImportJSON(str []byte) (err error) { return } - ifaceList := instance.IFaceList + ifaceList := instance.IfaceList var nodes []any // Prepare all ifaces based on the namespace @@ -132,8 +149,8 @@ func (instance *Instance) ImportJSON(str []byte) (err error) { // <- For Debugging cable := NewCable(linkPortA, linkPortB) - linkPortA.Cables = append(linkPortA.Cables, &cable) - linkPortB.Cables = append(linkPortB.Cables, &cable) + linkPortA.Cables = append(linkPortA.Cables, cable) + linkPortB.Cables = append(linkPortB.Cables, cable) cable.QConnected() // fmt.Println(cable.String()) @@ -161,7 +178,7 @@ func (instance *Instance) Settings(id string, val ...bool) bool { } func (instance *Instance) GetNode(id any) any { - for _, val := range instance.IFaceList { + for _, val := range instance.IfaceList { temp := reflect.ValueOf(val).Elem() if temp.FieldByName("Id").Interface().(string) == id || temp.FieldByName("I").Interface().(int) == id { return utils.GetProperty(val, "Node") @@ -173,7 +190,7 @@ func (instance *Instance) GetNode(id any) any { func (instance *Instance) GetNodes(namespace string) []any { var got []any // any = extends 'engine.Node' - for _, val := range instance.IFaceList { + for _, val := range instance.IfaceList { if utils.GetProperty(val, "Namespace").(string) == namespace { got = append(got, utils.GetProperty(val, "Node")) } @@ -195,7 +212,7 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes } // *iface: extends engine.Interface - iface := utils.GetProperty(node, "IFace") + iface := utils.GetProperty(node, "Iface") if iface == nil || utils.GetProperty(iface, "QInitialized").(bool) == false { panic(namespace + ": Node interface was not found, do you forget to call node->setInterface() ?") } @@ -218,11 +235,11 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes if options.Id != "" { utils.SetProperty(iface, "Id", options.Id) - instance.IFace[options.Id] = iface + instance.Iface[options.Id] = iface } utils.SetProperty(iface, "I", options.I) - instance.IFaceList[options.I] = iface + instance.IfaceList[options.I] = iface utils.SetProperty(iface, "Importing", false) utils.CallFunction(node, "Imported", utils.EmptyArgs) @@ -237,6 +254,22 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes return iface, nodes } +var createBPVariableRegx = regexp.MustCompile(`[` + "`" + `~!@#$%^&*()\-_+={}\[\]:"|;\'\\\\,.\/<>?]+`) + +func (instance *Instance) CreateVariable(id string) *BPVariable { + return &BPVariable{ + Id: id, + Title: id, + Type: 0, // Type not set + } + + // The type need to be defined dynamically on first cable connect +} + +func (instance *Instance) QLog(event NodeLog) { + fmt.Println(utils.GetProperty(event.Iface, "Title").(string) + "> " + event.Message) +} + // Currently only one level func deepMerge(real_ *InterfaceData, merge map[string]any) { real := *real_ diff --git a/engine/enums.go b/engine/enums.go new file mode 100644 index 0000000..c4df247 --- /dev/null +++ b/engine/enums.go @@ -0,0 +1,8 @@ +package engine + +/** For internal library use only */ +const ( + VarScopePublic = iota + 1 + VarScopePrivate + VarScopeShared +) diff --git a/engine/environment.go b/engine/environment.go new file mode 100644 index 0000000..f6d68a4 --- /dev/null +++ b/engine/environment.go @@ -0,0 +1,52 @@ +package engine + +import "regexp" + +type environment struct { + QNoEvent bool + Map map[string]string +} + +var QEnvironment = &environment{ + Map: map[string]string{}, +} + +// arr = ["KEY": "value"] +func (e *environment) Import(arr map[string]string) { + e.QNoEvent = true + for key, val := range arr { + e.Set(key, val) + } + e.QNoEvent = false + Event.Emit("environment.imported", nil) +} + +var envSetRegx = regexp.MustCompile(`[^A-Z_][^A-Z0-9_]`) + +type EnvironmentEvent struct { + Key string + Value string +} + +func (e *environment) Set(key string, val string) { + if len(envSetRegx.FindStringIndex(key)) > 0 { + panic("Environment must be uppercase and not contain any symbol except underscore, and not started by a number. But got: " + key) + } + + e.Map[key] = val + + if !e.QNoEvent { + Event.Emit("environment.added", &EnvironmentEvent{ + Key: key, + Value: val, + }) + } +} + +func (e *environment) Delete(key string) { + delete(e.Map, key) + Event.Emit("environment.deleted", &EnvironmentEvent{ + Key: key, + Value: "", + }) +} diff --git a/engine/interface.go b/engine/interface.go index 2ac32e9..5d7ba15 100644 --- a/engine/interface.go +++ b/engine/interface.go @@ -9,36 +9,52 @@ import ( var portList = [3]string{"Input", "Output", "Property"} -type InterfaceData map[string]GetterSetter +type InterfaceData map[string]getterSetter type Interface struct { - *customEvent - QInitialized bool // for internal library only + *CustomEvent Id string I int // index Title string Namespace string - Output map[string]*Port - Input map[string]*Port - Property map[string]*Port - Data InterfaceData - Node any // any = extends *engine.Node + // Property map[string]*Port + Output map[string]*Port + Input map[string]*Port + Data InterfaceData + Node any // any = extends *engine.Node - QRequesting bool // private (to be used for internal library only) - Importing bool + Ref *referencesShortcut + IsGhost bool + + Importing bool + + // for internal library use only + QInitialized bool + QRequesting bool + QFuncMain *NodesFunctionMain + QDynamicPort bool + QEnum int + QBpVarRef *BPVariable } // To be overriden -func (iface *Interface) Init() {} +func (iface *Interface) Init() {} +func (iface *Interface) Destroy() {} +func (iface *Interface) Imported(data any) {} var reflectKind = reflect.TypeOf(reflect.Int) // Private (to be called for internal library only) func (iface *Interface) QPrepare() { - iface.customEvent = &customEvent{} + iface.CustomEvent = &CustomEvent{} + ref := &referencesShortcut{} node := iface.Node + utils.SetProperty(node, "Ref", ref) + iface.Ref = ref + + utils.SetProperty(node, "Route", &RoutePort{Iface: iface}) for i := 0; i < 3; i++ { which := portList[i] @@ -56,79 +72,117 @@ func (iface *Interface) QPrepare() { if which == "Input" { inputUpgradePort = map[string]*PortInputGetterSetter{} + ref.Input = inputUpgradePort + ref.IInput = ifacePort + utils.SetProperty(node, which, inputUpgradePort) } else { outputUpgradePort = map[string]*PortOutputGetterSetter{} + ref.Output = outputUpgradePort + ref.IOutput = ifacePort + utils.SetProperty(node, which, outputUpgradePort) } // name: string for name, config_ := range port { - var config *PortFeature - var type_ reflect.Kind - var feature int - - var def any - if reflect.TypeOf(config_) == reflectKind { - type_ = config_.(reflect.Kind) - - if type_ == types.Int { - def = 0 - } else if type_ == types.Bool { - def = false - } else if type_ == types.String { - def = "" - } else if type_ == types.Array { - def = [0]any{} // ToDo: is this actually working? - } else if type_ == types.Any { // Any - // pass - } else if type_ == types.Function { - // pass - } else { - panic(iface.Namespace + ": '" + name + "' Port type(" + type_.String() + ") for initialization was not recognized") - } - } else { - config = config_.(*PortFeature) - type_ = config.Type - feature = config.Id - - if feature == PortTypeTrigger { - def = config.Func - type_ = types.Function - } else if feature == PortTypeArrayOf { - // pass - } else { - // panic(iface.Namespace + ": '" + name + "' Port feature(" + strconv.Itoa(feature) + ") for initialization was not recognized") - } - } + linkedPort := iface.QCreatePort(which, name, config_) + ifacePort[name] = linkedPort - var source int + // CreateLinker() if which == "Input" { - source = PortInput - } else if which == "Output" { - source = PortOutput + inputUpgradePort[name] = &PortInputGetterSetter{port: linkedPort} + } else { + outputUpgradePort[name] = &PortOutputGetterSetter{port: linkedPort} } - // else if which == "Property" { - // source = PortProperty - // } - - linkedPort := Port{ - Name: name, - Type: type_, - Default: def, - Source: source, - Iface: iface, - Feature: feature, + } + } +} + +func (iface *Interface) QCreatePort(which string, name string, config_ any) *Port { + var config *PortFeature + var type_ reflect.Kind + var types_ []reflect.Kind + var feature int + + var def any + if reflect.TypeOf(config_) == reflectKind { + type_ = config_.(reflect.Kind) + + if type_ == types.Int { + def = 0 + } else if type_ == types.Bool { + def = false + } else if type_ == types.String { + def = "" + } else if type_ == types.Array { + def = [0]any{} // ToDo: is this actually working? + } else if type_ == types.Any { // Any + // pass + } else if type_ == types.Function { + // pass + } else if type_ == types.Route { + // pass + } else { + panic(iface.Namespace + ": '" + name + "' Port type(" + type_.String() + ") for initialization was not recognized") + } + } else { + config = config_.(*PortFeature) + type_ = config.Type + feature = config.Id + + if feature == PortTypeTrigger { + def = config.Func + type_ = types.Function + } else if feature == PortTypeArrayOf { + if type_ != types.Any { + def = &[]any{} } + } else if feature == PortTypeUnion { + types_ = config.Types + } else if feature == PortTypeDefault { + def = config.Value + } else { + // panic(iface.Namespace + ": '" + name + "' Port feature(" + strconv.Itoa(feature) + ") for initialization was not recognized") + } + } - ifacePort[name] = &linkedPort + var source int + if which == "Input" { + source = PortInput + } else if which == "Output" { + source = PortOutput + } + // else if which == "Property" { + // source = PortProperty + // } + + return &Port{ + Name: name, + Type: type_, + Types: types_, + Default: def, + Source: source, + Iface: iface, + Feature: feature, + } +} - // CreateLinker() - if which == "Input" { - inputUpgradePort[name] = &PortInputGetterSetter{port: &linkedPort} - } else { - outputUpgradePort[name] = &PortOutputGetterSetter{port: &linkedPort} - } +func (iface *Interface) QInitPortSwitches(portSwitches map[string]int) { + for key, val := range portSwitches { + if (val | 1) == 1 { + portStructOf_split(iface.Output[key]) + } + + if (val | 2) == 2 { + iface.Output[key].AllowResync = true } } } + +// Load saved port data value +func (iface *Interface) QImportInputs(ports map[string]*Port) { + for key, val := range ports { + iface.Input[key].Default = val + } +} diff --git a/engine/node.go b/engine/node.go index 7a98941..411b413 100644 --- a/engine/node.go +++ b/engine/node.go @@ -1,22 +1,28 @@ package engine import ( + "reflect" + "github.com/blackprint/engine-go/utils" ) type Node struct { - *customEvent - Instance *Instance - IFace any // any = extends *engine.Interface + *CustomEvent + Instance *Instance + Iface any // any = extends *engine.Interface + DisablePorts bool + Routes RoutePort + + Ref *referencesShortcut // Port Template - TOutput map[string]any // any = port.Type or *port.Feature - TInput map[string]any // any = port.Type or *port.Feature - TProperty map[string]any // any = port.Type or *port.Feature + TOutput map[string]any // any = port.Type or *port.Feature + TInput map[string]any // any = port.Type or *port.Feature + // TProperty map[string]any // any = port.Type or *port.Feature Output map[string]*PortOutputGetterSetter Input map[string]*PortInputGetterSetter - // Property map[string]GetterSetter + // Property map[string]getterSetter } type NodeHandler func(*Instance) any // any = extends *engine.Node @@ -34,8 +40,8 @@ func (n *Node) SetInterface(namespace ...string) any { // Default interface (BP/Default) iface := &Interface{QInitialized: true, Importing: true} - n.IFace = iface - n.customEvent = &customEvent{} + n.Iface = iface + n.CustomEvent = &CustomEvent{} return iface } @@ -55,20 +61,117 @@ func (n *Node) SetInterface(namespace ...string) any { _data := data.(InterfaceData) for _, port := range _data { - utils.SetProperty(port, "IFace", iface) + utils.SetProperty(port, "Iface", iface) } } utils.SetProperty(iface, "QInitialized", true) utils.SetProperty(iface, "Importing", true) - n.IFace = iface - n.customEvent = &customEvent{} + n.Iface = iface + n.CustomEvent = &CustomEvent{} return iface } -// To be overriden -func (n *Node) Init() {} -func (n *Node) Request(*Port, any) {} // any => extends engine.Interface -func (n *Node) Update(*Cable) {} -func (n *Node) Imported() {} +func (n *Node) CreatePort(which string, name string, config_ any) *Port { + port := utils.CallFunction(n.Iface, "QCreatePort", &[]reflect.Value{ + reflect.ValueOf(which), + reflect.ValueOf(name), + reflect.ValueOf(config_), + }).(*Port) + + if which != "input" { + ifacePort := utils.GetProperty(n.Iface, "Input").(map[string]*Port) + ifacePort[name] = port + n.Input[name] = &PortInputGetterSetter{port: port} + } else if which != "output" { + ifacePort := utils.GetProperty(n.Iface, "Output").(map[string]*Port) + ifacePort[name] = port + n.Output[name] = &PortOutputGetterSetter{port: port} + } else { + panic("Can only create port for 'input' and 'output'") + } + + return port +} + +func (n *Node) RenamePort(which string, name string, to string) { + var portList map[string]*Port + if which == "input" { + portList = utils.GetProperty(n.Iface, "Input").(map[string]*Port) + } else if which == "output" { + portList = utils.GetProperty(n.Iface, "Output").(map[string]*Port) + } else { + panic("Can only rename port for 'input' and 'output'") + } + + port := portList[name] + if port == nil { + panic(which + " port with name '" + name + "' was not found") + } + + if portList[to] != nil { + panic(which + " port with name '" + to + "' already exist") + } + + portList[to] = port + delete(portList, name) + + port.Name = to + + if which == "input" { + n.Input[to] = n.Input[name] + delete(n.Input, name) + } else if which == "output" { + n.Output[to] = n.Output[name] + delete(n.Output, name) + } +} + +func (n *Node) DeletePort(which string, name string) { + var ports map[string]*Port + var port *Port + + if which != "input" { + ports = utils.GetProperty(n.Iface, "Input").(map[string]*Port) + port = ports[name] + if port == nil { + return + } + + delete(n.Input, name) + } else if which != "output" { + ports = utils.GetProperty(n.Iface, "Output").(map[string]*Port) + port = ports[name] + if port == nil { + return + } + + delete(n.Output, name) + } else { + panic("Can only delete port for 'input' and 'output'") + } + + port.DisconnectAll() + delete(ports, name) +} + +type NodeLog struct { + Iface any + Message string +} + +func (n *Node) Log(message string) { + n.Instance.QLog(NodeLog{ + Iface: n.Iface, + Message: message, + }) +} + +// To be overriden by module developer +func (n *Node) Init() {} +func (n *Node) Request(*Cable) {} +func (n *Node) Update(*Cable) {} +func (n *Node) Imported(map[string]any) {} +func (n *Node) Destroy() {} +func (n *Node) SyncOut(id string, data ...any) {} diff --git a/engine/nodes/enums.go b/engine/nodes/enums.go new file mode 100644 index 0000000..2a409b4 --- /dev/null +++ b/engine/nodes/enums.go @@ -0,0 +1,13 @@ +package nodes + +const ( + BPEnvGet = iota + 1 + BPEnvSet + BPVarGet + BPVarSet + BPFnVarInput + BPFnVarOutput + BPFnInput + BPFnOutput + BPFnMain +) diff --git a/engine/port.go b/engine/port.go index 2d8238e..662bd25 100644 --- a/engine/port.go +++ b/engine/port.go @@ -6,24 +6,42 @@ import ( "github.com/blackprint/engine-go/utils" ) +type PortStructTemplate struct { + Type any + Field string + Handle func(any) any +} + type Port struct { - customEvent - Name string - Type reflect.Kind - Cables []*Cable - Source int - Iface *Interface - Default any // Dynamic data (depend on Type) for storing port value (int, string, map, etc..) - Value any // Dynamic data (depend on Type) for storing port value (int, string, map, etc..) - Func func(any) - Sync bool - Feature int + CustomEvent + Name string + Type reflect.Kind + Types []reflect.Kind + Cables []*Cable + Source int + Iface any + Default any // Dynamic data (depend on Type) for storing port value (int, string, map, etc..) + Value any // Dynamic data (depend on Type) for storing port value (int, string, map, etc..) + Func func(any) + Sync bool + Feature int + Struct map[string]PortStructTemplate + Splitted bool + AllowResync bool + + // Only in Golang we need to do this '-' + RoutePort *RoutePort + + // Internal/Private property + QCache any + QParent *Port + QStructSplitted bool } const ( PortInput = iota + 1 PortOutput - PortProperty + // PortProperty ) const ( @@ -45,7 +63,7 @@ type PortFeature struct { } type PortInputGetterSetter struct { - GetterSetter + getterSetter port *Port } @@ -152,7 +170,7 @@ func (gs *PortInputGetterSetter) Get() any { } type PortOutputGetterSetter struct { - GetterSetter + getterSetter port *Port } @@ -167,7 +185,7 @@ func (gs *PortOutputGetterSetter) Set(val any) { // fmt.Printf("3. %s = %s\n", port.Name, val) port.Value = val - port.QTrigger("value", port) + port.Emit("value", port) port.sync() } @@ -206,7 +224,7 @@ func (gs *PortOutputGetterSetter) Get() any { return port.Value } -func (port *Port) CreateLinker() GetterSetter { +func (port *Port) CreateLinker() getterSetter { if port.Source == PortInput { return &PortInputGetterSetter{port: port} } @@ -229,6 +247,6 @@ func (port *Port) sync() { }) } - target.QTrigger("value", port) + target.Emit("value", port) } } diff --git a/engine/portFeature.go b/engine/portFeature.go new file mode 100644 index 0000000..60bdcee --- /dev/null +++ b/engine/portFeature.go @@ -0,0 +1,97 @@ +package engine + +import ( + "reflect" + + "github.com/blackprint/engine-go/types" + "github.com/blackprint/engine-go/utils" +) + +func portArrayOf_validate(source *Port, target *Port) bool { + if source.Type == target.Type || source.Type == types.Any || target.Type == types.Any { + return true + } + + if source.Types != nil && utils.Contains(source.Types, target.Type) { + return true + } + + return false +} + +func portUnion_validate(source *Port, target *Port) bool { + if source.Types != nil && target.Types != nil { + if len(source.Types) != len(target.Types) { + return false + } + + for _, type_ := range source.Types { + if !utils.Contains(target.Types, type_) { + return false + } + } + + return true + } + + return target.Type == types.Any || utils.Contains(source.Types, target.Type) +} + +func portStructOf_split(port *Port) { + if port.Source == PortInput { + panic("Port with feature 'StructOf' only supported for output port") + } + + node := port.Iface.Node + struct_ := &port.Struct + + for key, val := range *struct_ { + name := port.Name + key + newPort := node.CreatePort("output", name, val.Type) + newPort.QParent = port + newPort.QStructSplitted = true + } + + port.Splitted = true + port.DisconnectAll() + + portData := utils.GetProperty(node, "Output").(map[string]*PortOutputGetterSetter)[port.Name] + if portData != nil { + portStructOf_handle(port, portData) + } +} + +func portStructOf_unsplit(port *Port) { + parent := port.QParent + if parent == nil && port.Struct != nil { + parent = port + } + + parent.Splitted = false + node := port.Iface.Node + + for key, _ := range parent.Struct { + utils.CallFunction(node, "DeletePort", &[]reflect.Value{ + reflect.ValueOf("output"), + reflect.ValueOf(parent.Name + key), + }) + } +} + +func portStructOf_handle(port *Port, data any) { + output := utils.GetProperty(port.Iface.Node, "Output").(map[string]*PortOutputGetterSetter) + + if data != nil { + for key, val := range port.Struct { + if val.Field == "" { + output[key].Set(utils.GetProperty(data, val.Field)) + } else { + output[key].Set(val.Handle(data)) + } + } + } else { + for key, _ := range port.Struct { + output[key].Set(nil) + } + } +} diff --git a/engine/portGhost.go b/engine/portGhost.go new file mode 100644 index 0000000..111d114 --- /dev/null +++ b/engine/portGhost.go @@ -0,0 +1,19 @@ +package engine + +var fakeIface = &Interface{ + Title: "Blackprint.PortGhost", + IsGhost: true, + Node: &Node{ + Instance: &Instance{}, + }, +} + +func OutputPort(type_ any) *Port { + port := fakeIface.QCreatePort("Output", "Blackprint.OutputPort", type_) + return port +} + +func InputPort(type_ any) *Port { + port := fakeIface.QCreatePort("Input", "Blackprint.InputPort", type_) + return port +} diff --git a/engine/references.go b/engine/references.go new file mode 100644 index 0000000..7b66f16 --- /dev/null +++ b/engine/references.go @@ -0,0 +1,8 @@ +package engine + +type referencesShortcut struct { + IInput map[string]*Port + Input map[string]*PortInputGetterSetter + IOutput map[string]*Port + Output map[string]*PortOutputGetterSetter +} diff --git a/engine/routePort.go b/engine/routePort.go new file mode 100644 index 0000000..80ad5f8 --- /dev/null +++ b/engine/routePort.go @@ -0,0 +1,115 @@ +package engine + +import ( + "reflect" + + "github.com/blackprint/engine-go/engine/nodes" + "github.com/blackprint/engine-go/utils" +) + +type RoutePort struct { + *Port + In []*Cable + Out *Cable + DisableOut bool + Disabled bool + IsRoute bool + Iface any // any = extends *engine.Interface + + // for internal library use only + QIsPaused bool +} + +func newRoutePort(iface any) *RoutePort { + temp := &RoutePort{ + Iface: iface, + IsRoute: true, + } + temp.Port = &Port{RoutePort: temp, Iface: iface} + temp.Port.Cables = []*Cable{} + temp.In = temp.Port.Cables + return temp +} + +// Connect other route port (this .out to other .in port) +func (r *RoutePort) RouteTo(iface any) { + if r.Out != nil { + r.Out.Disconnect() + } + + if iface == nil { + cable := NewCable(r.Port, nil) + cable.IsRoute = true + r.Out = cable + return + } + + port := utils.GetProperty(utils.GetProperty(iface, "Node"), "Routes").(*RoutePort) + + cable := NewCable(r.Port, port.Port) + cable.IsRoute = true + cable.Output = r.Port + r.Out = cable + port.In = append(port.In, cable) // ToDo: check if this empty if the connected cable was disconnected + + cable.QConnected() +} + +func (r *RoutePort) ConnectCable(cable *Cable) bool { + if utils.Contains(r.In, cable) { + return false + } + + r.In = append(r.In, cable) + cable.Input = r.Port + cable.Target = r.Port + cable.QConnected() + + return true +} + +func (r *RoutePort) RouteIn(cable *Cable) { + node := utils.GetProperty(r.Iface, "Node") + utils.CallFunction(node, "Update", &[]reflect.Value{ + reflect.ValueOf(cable), + }) + + routes := utils.GetProperty(node, "Routes") + utils.CallFunction(routes, "RouteOut", nil) +} + +func (r *RoutePort) RouteOut() { + if r.DisableOut { + return + } + + if r.Out == nil { + if utils.GetProperty(r.Iface, "QEnum").(int) == nodes.BPFnOutput { + node := utils.GetProperty(utils.GetProperty(r.Iface, "QFuncMain"), "Node") + route := utils.GetProperty(node, "Routes").(*RoutePort) + utils.CallFunction(route, "RouteIn", nil) + } + + return + } + + targetRoute := r.Out.Input.RoutePort + if targetRoute == nil { + return + } + + enum := utils.GetProperty(targetRoute.Iface, "QEnum").(int) + + if enum == 0 { + targetRoute.RouteIn(r.Out) + } else if enum == nodes.BPFnMain { + routes := utils.GetProperty(utils.GetProperty(targetRoute.Iface, "QProxyInput"), "Routes").(*RoutePort) + routes.RouteIn(r.Out) + } else if enum == nodes.BPFnOutput { + node := utils.GetProperty(utils.GetProperty(targetRoute.Iface, "QFuncMain"), "Node") + routes := utils.GetProperty(node, "Routes").(*RoutePort) + routes.RouteIn(r.Out) + } else { + targetRoute.RouteIn(r.Out) + } +} diff --git a/example/button.go b/example/button.go index 0831451..d0ff54d 100644 --- a/example/button.go +++ b/example/button.go @@ -24,7 +24,7 @@ func (iface *ButtonSimpleIFace) Clicked(ev any) { // This will be called from example.go func RegisterButton() { - ButtonSimpleOutput := engine.NodePort{ + ButtonSimpleOutput := engine.NodePortTemplate{ "Clicked": types.Function, } diff --git a/example/example_test.go b/example/example_test.go index 7a2e7fd..3e24ba0 100644 --- a/example/example_test.go +++ b/example/example_test.go @@ -23,24 +23,25 @@ func TestMain(m *testing.M) { // You can import the JSON to Blackprint Sketch if you want to view the nodes visually instance = engine.New() json := `{"Example/Math/Random":[{"i":0,"x":298,"y":73,"output":{"Out":[{"i":2,"name":"A"}]}},{"i":1,"x":298,"y":239,"output":{"Out":[{"i":2,"name":"B"}]}}],"Example/Math/Multiply":[{"i":2,"x":525,"y":155,"output":{"Result":[{"i":3,"name":"Any"}]}}],"Example/Display/Logger":[{"i":3,"id":"myLogger","x":763,"y":169}],"Example/Button/Simple":[{"i":4,"id":"myButton","x":41,"y":59,"output":{"Clicked":[{"i":2,"name":"Exec"}]}}],"Example/Input/Simple":[{"i":5,"id":"myInput","x":38,"y":281,"data":{"value":"saved input"},"output":{"Changed":[{"i":1,"name":"Re-seed"}],"Value":[{"i":3,"name":"Any"}]}}]}` + // json := `{"_":{"moduleJS":["http://localhost:6789/dist/nodes-example.mjs"],"functions":{"Test":{"id":"Test","title":"Test","description":"No description","vars":["shared"],"privateVars":["private"],"structure":{"BP/Fn/Input":[{"i":0,"x":389,"y":100,"z":3,"output":{"A":[{"i":2,"name":"A"}],"Exec":[{"i":2,"name":"Exec"}]}}],"BP/Fn/Output":[{"i":1,"x":973,"y":228,"z":14}],"Example/Math/Multiply":[{"i":2,"x":656,"y":99,"z":8,"output":{"Result":[{"i":3,"name":"Val"},{"i":9,"name":"Val"}]}},{"i":10,"x":661,"y":289,"z":4,"output":{"Result":[{"i":5,"name":"Val"},{"i":1,"name":"Result1"}]}}],"BP/Var/Set":[{"i":3,"x":958,"y":142,"z":9,"data":{"name":"shared","scope":2}},{"i":5,"x":971,"y":333,"z":2,"data":{"name":"private","scope":1},"route":{"i":1}}],"BP/Var/Get":[{"i":4,"x":387,"y":461,"z":5,"data":{"name":"shared","scope":2},"output":{"Val":[{"i":8,"name":"Any"}]}},{"i":6,"x":389,"y":524,"z":0,"data":{"name":"private","scope":1},"output":{"Val":[{"i":8,"name":"Any"}]}}],"BP/FnVar/Input":[{"i":7,"x":387,"y":218,"z":7,"data":{"name":"B"},"output":{"Val":[{"i":2,"name":"B"}]}},{"i":11,"x":386,"y":301,"z":6,"data":{"name":"Exec"},"output":{"Val":[{"i":10,"name":"Exec"}]}},{"i":12,"x":386,"y":370,"z":10,"data":{"name":"A"},"output":{"Val":[{"i":10,"name":"A"},{"i":10,"name":"B"}]}}],"Example/Display/Logger":[{"i":8,"x":661,"y":474,"z":11}],"BP/FnVar/Output":[{"i":9,"x":956,"y":69,"z":1,"data":{"name":"Result"}},{"i":14,"x":969,"y":629,"z":13,"data":{"name":"Clicked"}}],"Example/Button/Simple":[{"i":13,"x":634,"y":616,"z":12,"output":{"Clicked":[{"i":14,"name":"Val"}]}}]}}}},"Example/Math/Random":[{"i":0,"x":512,"y":76,"z":0,"output":{"Out":[{"i":5,"name":"A"}]},"route":{"i":5}},{"i":1,"x":512,"y":242,"z":1,"output":{"Out":[{"i":5,"name":"B"}]}}],"Example/Display/Logger":[{"i":2,"x":986,"y":282,"z":2,"id":"myLogger"}],"Example/Button/Simple":[{"i":3,"x":244,"y":64,"z":6,"id":"myButton","output":{"Clicked":[{"i":5,"name":"Exec"}]}}],"Example/Input/Simple":[{"i":4,"x":238,"y":279,"z":4,"id":"myInput","data":{"value":"saved input"},"output":{"Changed":[{"i":1,"name":"Re-seed"}],"Value":[{"i":2,"name":"Any"}]}}],"BPI/F/Test":[{"i":5,"x":738,"y":138,"z":5,"output":{"Result1":[{"i":2,"name":"Any"}],"Result":[{"i":2,"name":"Any"}],"Clicked":[{"i":6,"name":"Exec"}]},"route":{"i":6}}],"Example/Math/Multiply":[{"i":6,"x":1032,"y":143,"z":3}]}` instance.ImportJSON([]byte(json)) // Because Golang lack of getter and setter, We need to get or set like calling a function // Anyway.. lets to run something :) - button := instance.IFace["myButton"].(*ButtonSimpleIFace) + button := instance.Iface["myButton"].(*ButtonSimpleIFace) log.Println("\n>> I'm clicking the button") button.Clicked(123) - logger := instance.IFace["myLogger"].(*LoggerIFace) + logger := instance.Iface["myLogger"].(*LoggerIFace) log.Println("\n>> I got the output value: " + logger.Log().(string)) log.Println("\n>> I'm writing something to the input box") - input = instance.IFace["myInput"].(*InputSimpleIFace) + input = instance.Iface["myInput"].(*InputSimpleIFace) input.Data["value"].Set("hello wrold") // you can also use getNodes if you haven't set the ID - myLogger := instance.GetNodes("Example/Display/Logger")[0].(*LoggerNode).IFace.(*LoggerIFace) + myLogger := instance.GetNodes("Example/Display/Logger")[0].(*LoggerNode).Iface.(*LoggerIFace) log.Println("\n>> I got the output value: " + myLogger.Log().(string)) } diff --git a/example/input.go b/example/input.go index fb9b6b2..b0fc4af 100644 --- a/example/input.go +++ b/example/input.go @@ -15,7 +15,7 @@ type InputSimple struct { // Bring value from imported iface to node output func (node *InputSimple) Imported() { - val := node.IFace.(*InputSimpleIFace).Data["value"].Get() + val := node.Iface.(*InputSimpleIFace).Data["value"].Get() if val != nil { log.Printf("\x1b[1m\x1b[33mInput\\Simple:\x1b[0m \x1b[33mSaved data as output: %s\x1b[0m\n", val) } @@ -43,13 +43,13 @@ func (iface *InputSimpleIFace) Changed(val any) { } type MyData struct { - IFace any + Iface any val any } func (gs *MyData) Set(val any) { gs.val = val - gs.IFace.(*InputSimpleIFace).Changed(gs.val) + gs.Iface.(*InputSimpleIFace).Changed(gs.val) } func (gs *MyData) Get() any { @@ -64,7 +64,7 @@ func RegisterInput() { Instance: instance, // Node's Output Port Template - TOutput: engine.NodePort{ + TOutput: engine.NodePortTemplate{ "Changed": types.Function, "Value": types.String, }, diff --git a/example/logger.go b/example/logger.go index 2a9be62..32739e9 100644 --- a/example/logger.go +++ b/example/logger.go @@ -76,7 +76,7 @@ func RegisterLogger() { Instance: instance, // Node's Input Port Template - TInput: engine.NodePort{ + TInput: engine.NodePortTemplate{ "Any": port.ArrayOf(reflect.Interface), // nil => Any }, }, diff --git a/example/math.go b/example/math.go index 5e3c550..f788335 100644 --- a/example/math.go +++ b/example/math.go @@ -44,14 +44,14 @@ func RegisterMathMultiply() { Instance: instance, // Node's Input Port Template - TInput: engine.NodePort{ + TInput: engine.NodePortTemplate{ "Exec": port.Trigger(func(port *engine.Port) { node.Output["Result"].Set(node.Multiply()) log.Printf("\x1b[1m\x1b[33mMath\\Multiply:\x1b[0m \x1b[33mResult has been set: %d\x1b[0m\n", node.Output["Result"].Get()) }), "A": types.Int, "B": port.Validator(types.Int, func(val any) any { - log.Printf("\x1b[1m\x1b[33mMath\\Multiply:\x1b[0m \x1b[33m%s - Port B got input: %d\x1b[0m\n", node.IFace.(*engine.Interface).Title, val) + log.Printf("\x1b[1m\x1b[33mMath\\Multiply:\x1b[0m \x1b[33m%s - Port B got input: %d\x1b[0m\n", node.Iface.(*engine.Interface).Title, val) // Convert string to number if reflect.ValueOf(val).Kind() == reflect.String { @@ -64,7 +64,7 @@ func RegisterMathMultiply() { }, // Node's Output Port Template - TOutput: engine.NodePort{ + TOutput: engine.NodePortTemplate{ "Result": types.Int, }, }, @@ -114,7 +114,7 @@ func RegisterMathRandom() { Instance: instance, // Node's Input Port Template - TInput: engine.NodePort{ + TInput: engine.NodePortTemplate{ "Re-seed": port.Trigger(func(port *engine.Port) { node.Executed = true byt := make([]byte, 2) @@ -124,7 +124,7 @@ func RegisterMathRandom() { }, // Node's Output Port Template - TOutput: engine.NodePort{ + TOutput: engine.NodePortTemplate{ "Out": types.Int, }, }, diff --git a/go.mod b/go.mod index cf28165..7a31b5e 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/blackprint/engine-go go 1.19 require ( - github.com/inconshreveable/mousetrap v1.0.0 // indirect - github.com/spf13/cobra v1.2.1 // indirect + github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/spf13/cobra v1.5.0 // indirect github.com/spf13/pflag v1.0.5 // indirect ) diff --git a/go.sum b/go.sum index 9290f91..eb38d7c 100644 --- a/go.sum +++ b/go.sum @@ -56,6 +56,7 @@ github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnht github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -160,6 +161,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= @@ -195,6 +198,7 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -204,6 +208,8 @@ github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= +github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= diff --git a/internal/cmd/root.go b/internal/cmd/root.go index 84cb56e..f34d8a7 100644 --- a/internal/cmd/root.go +++ b/internal/cmd/root.go @@ -6,6 +6,6 @@ var ( RootCmd = &cobra.Command{ Use: "engine-go", Short: "engine-go for Blackprint", - Long: "engine-go is Blackprint engine", + Long: "engine-go is Blackprint Engine for Golang", } ) diff --git a/types/types.go b/types/types.go index e637507..5da1d95 100644 --- a/types/types.go +++ b/types/types.go @@ -12,4 +12,5 @@ const ( Int = reflect.Int64 Float = reflect.Float64 Any = reflect.Interface + Route = 99999 // ToDo: do we need to fix this magic number? ) diff --git a/utils/utils.go b/utils/utils.go index b75890a..ab471fe 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -43,3 +43,35 @@ func CallFieldFunction(obj any, key string, val *[]reflect.Value) any { func HasProperty(obj any, key string) bool { return reflect.ValueOf(obj).Elem().FieldByName(key).IsValid() } + +// https://stackoverflow.com/a/71184501/6563200 +func IndexOf[T comparable](collection []T, el T) int { + for i, x := range collection { + if x == el { + return i + } + } + return -1 +} + +func Contains[T comparable](collection []T, el T) bool { + for _, x := range collection { + if x == el { + return true + } + } + return false +} + +func RemoveItem[T comparable](collection []T, el T) []T { + i := IndexOf(collection, el) + if i == -1 { + return collection + } + + return append(collection[:i], collection[i+1:]...) +} + +func RemoveItemAtIndex[T comparable](collection []T, i int) []T { + return append(collection[:i], collection[i+1:]...) +} From 42ec4f24b28b39134832ba9d18a31ab01fe6b503 Mon Sep 17 00:00:00 2001 From: StefansArya Date: Wed, 7 Sep 2022 18:02:13 +0700 Subject: [PATCH 02/15] Change port features --- engine/port.go | 19 ++++++++++++++----- port/types.go | 31 +++++++++++++------------------ 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/engine/port.go b/engine/port.go index 662bd25..38702c1 100644 --- a/engine/port.go +++ b/engine/port.go @@ -15,6 +15,7 @@ type PortStructTemplate struct { type Port struct { CustomEvent Name string + Name_ *RefPortName // ToDo: fill alternate name, search in engine-php _name for hints Type reflect.Kind Types []reflect.Kind Cables []*Cable @@ -22,7 +23,7 @@ type Port struct { Iface any Default any // Dynamic data (depend on Type) for storing port value (int, string, map, etc..) Value any // Dynamic data (depend on Type) for storing port value (int, string, map, etc..) - Func func(any) + Func func(*Port) Sync bool Feature int Struct map[string]PortStructTemplate @@ -38,6 +39,10 @@ type Port struct { QStructSplitted bool } +type RefPortName struct { + Name string +} + const ( PortInput = iota + 1 PortOutput @@ -47,10 +52,10 @@ const ( const ( PortTypeArrayOf = iota + 1 PortTypeDefault - PortTypeSwitch PortTypeTrigger PortTypeUnion - PortTypeValidator + PortTypeStructOf + PortTypeRoute ) // Port feature @@ -185,7 +190,9 @@ func (gs *PortOutputGetterSetter) Set(val any) { // fmt.Printf("3. %s = %s\n", port.Name, val) port.Value = val - port.Emit("value", port) + port.Emit("value", &PortSelfEvent{ + Port: port, + }) port.sync() } @@ -247,6 +254,8 @@ func (port *Port) sync() { }) } - target.Emit("value", port) + target.Emit("value", &PortSelfEvent{ + Port: port, + }) } } diff --git a/port/types.go b/port/types.go index d5b300b..bf4c19c 100644 --- a/port/types.go +++ b/port/types.go @@ -3,7 +3,7 @@ package port import ( "reflect" - engine "github.com/blackprint/engine-go/engine" + "github.com/blackprint/engine-go/engine" ) /* This port can contain multiple cable as input @@ -30,16 +30,6 @@ func Default(type_ reflect.Kind, val any) *engine.PortFeature { } } -/* Allow many cable connected to a port - * But only the last value that will used as value - */ -func Switch(type_ reflect.Kind) *engine.PortFeature { - return &engine.PortFeature{ - Id: engine.PortTypeSwitch, - Type: type_, - } -} - /* This port will be used as a trigger or callable input port * func = callback when the port was being called as a function */ @@ -60,14 +50,19 @@ func Union(types []reflect.Kind) *engine.PortFeature { } } -/* This port will allow any value to be passed to a function - * then you can write custom data validation in the function - * the value returned by your function will be used as the input value +/* This port can allow multiple different types + * like an 'any' port, but can only contain one value */ -func Validator(type_ reflect.Kind, callback func(any) any) *engine.PortFeature { +func StructOf(type_ reflect.Kind, structure map[string]engine.PortStructTemplate) *engine.PortFeature { return &engine.PortFeature{ - Id: engine.PortTypeValidator, - Type: type_, - Func: callback, + Id: engine.PortTypeStructOf, + Type: type_, + Value: structure, + } +} + +func Route() *engine.PortFeature { + return &engine.PortFeature{ + Id: engine.PortTypeRoute, } } From e03f12b485703707d33f4e96549cb4003a055d28 Mon Sep 17 00:00:00 2001 From: StefansArya Date: Wed, 7 Sep 2022 18:02:45 +0700 Subject: [PATCH 03/15] Add `nodesFnPortVar.go` and change stuff --- blackprint/blackprint.go | 7 + blackprint/nodesEnvironment.go | 4 +- blackprint/nodesFnPortVar.go | 332 ++++++++++++++++++++++++++++++++- engine/engine.go | 2 +- engine/interface.go | 4 +- engine/node.go | 4 +- engine/references.go | 2 +- example/example.go | 4 +- example/example_test.go | 2 +- 9 files changed, 348 insertions(+), 13 deletions(-) diff --git a/blackprint/blackprint.go b/blackprint/blackprint.go index 8e67618..da5981d 100644 --- a/blackprint/blackprint.go +++ b/blackprint/blackprint.go @@ -22,3 +22,10 @@ func RegisterInterface(namespace string, constructor func(any) any) { var Event = engine.Event var Environment = engine.QEnvironment + +func init() { + registerEnvNode() + registerBpPortVarNode() + registerBpFuncNode() + registerBpPortVarNode() +} diff --git a/blackprint/nodesEnvironment.go b/blackprint/nodesEnvironment.go index b6ab169..96947d0 100644 --- a/blackprint/nodesEnvironment.go +++ b/blackprint/nodesEnvironment.go @@ -7,12 +7,10 @@ import ( type bpEnvGet struct { *engine.Node - Iface *engine.Interface } type bpEnvSet struct { *engine.Node - Iface *engine.Interface } func (b *bpEnvSet) Update(c *engine.Cable) { @@ -42,7 +40,7 @@ type iEnvGet struct { } func (b *iEnvGet) Imported(data map[string]any) { - b.Imported(data) + b.bpEnvGetSet.Imported(data) b.QListener = func(v any) { ev := v.(*engine.EnvironmentEvent) diff --git a/blackprint/nodesFnPortVar.go b/blackprint/nodesFnPortVar.go index aede51b..c0dfa00 100644 --- a/blackprint/nodesFnPortVar.go +++ b/blackprint/nodesFnPortVar.go @@ -1,5 +1,335 @@ package blackprint -func registerBpPortVarNode() { +import ( + "strconv" + "github.com/blackprint/engine-go/engine" + "github.com/blackprint/engine-go/engine/nodes" + portTypes "github.com/blackprint/engine-go/port" + "github.com/blackprint/engine-go/types" +) + +type fnVarInput struct { + *engine.Node +} + +func (f *fnVarInput) Imported(data map[string]any) { + if f.Routes != nil { + f.Routes.Disabled = true + } +} + +func (f *fnVarInput) Request(cable *engine.Cable) { + iface := f.Iface + + // This will trigger the port to request from outside and assign to this node's port + f.Output["Val"].Set(iface.QParentFunc.Node.Input[iface.Data["name"].Get().(string)]) +} + +type fnVarOutput struct { + *engine.Node +} + +func (f *fnVarOutput) Update(c *engine.Cable) { + id := f.Iface.Data["name"].Get() + f.RefOutput[id].Set(f.Ref.Input["Val"].Get()) +} + +type bpFnVarInOut struct { + *engine.Interface + OnConnect func(*engine.Cable, *engine.Port) + + QParentFunc any // => *engine.Interface + QProxyIface any + QListener func(any) + QWaitPortInit func(*engine.Port) +} + +func (f *bpFnVarInOut) Imported(data map[string]any) { + if data["name"] == nil { + panic("Parameter 'name' is required") + } + + b.Data["name"].Set(data["name"]) + f.QParentFunc = f.Node.Instance.QFuncMain +} + +type fnVarInputIface struct { + *bpFnVarInOut +} + +func (f *fnVarInputIface) Imported(data map[string]any) { + f.bpFnVarInOut.Imported(data) + ports := f.QParentFunc.Ref.IInput + node := f.Node + + f.QProxyIface = f.QParentFunc.QProxyInput.Iface + + // Create temporary port if the main function doesn't have the port + name := data["name"].(string) + if _, exist := ports[name]; !exist { + iPort := node.CreatePort("input", "Val", types.Any) + proxyIface := f.QProxyIface + + // Run when $this node is being connected with other node + iPort.OnConnect = func(cable *engine.Cable, port *engine.Port) { + iPort.OnConnect = nil + proxyIface.Off("_add."+name, iPort.QWaitPortInit) + iPort.QWaitPortInit = nil + + cable.Disconnect() + node.DeletePort("output", "Val") + + portName := &engine.RefPortName{Name: name} + portType := getFnPortType(port, "input", f.QParentFunc, portName) + newPort := node.CreatePort("output", "Val", portType) + newPort.Name_ = portName + newPort.ConnectPort(port) + + proxyIface.AddPort(port, name) + f.QAddListener() + } + + // Run when main node is the missing port + iPort.QWaitPortInit = func(port *engine.Port) { + iPort.OnConnect = nil + iPort.QWaitPortInit = nil + + backup := []*engine.Port{} + for _, val := range f.Output["Val"].Cables { + backup = append(backup, val.Input) + } + + node := f.Node + node.DeletePort("output", "Val") + + portType := getFnPortType(port, "input", f.QParentFunc, port.Name_) + + newPort := node.CreatePort("output", "Val", portType) + f.QAddListener() + + for _, val := range backup { + newPort.ConnectPort(val) + } + } + + proxyIface.Once("_add."+name, iPort.QWaitPortInit) + } else { + if _, exist := f.Output["Val"]; !exist { + port := ports[name] + portType := getFnPortType(port, "input", f.QParentFunc, port.Name_) + newPort := node.CreatePort("input", "Val", portType) + } + + f.QAddListener() + } +} + +func (f *fnVarInputIface) QAddListener() { + port := f.QProxyIface.Output[f.Data["name"].Get().(string)].(*engine.Port) + + if port.Feature == engine.PortTypeTrigger { + f.QListener = func(p any) { + f.Ref.Output["Val"].Call() + } + + port.On("call", f.QListener) + } else { + f.QListener = func(ev any) { + port := ev.(*engine.PortSelfEvent).Port + if port.Iface.Node.Routes.Out == nil { + val := f.Ref.IOutput["Val"] + val.Value = port.Value // Change value without trigger node.update + + for _, temp := range val.Cables { + // Clear connected cable's cache + temp.Input.QCache = nil + } + return + } + + f.Ref.Output["Val"].Set(port.Value) + } + + port.On("value", f.QListener) + } +} + +func (f *fnVarInputIface) Destroy() { + f.bpFnVarInOut.Destroy() + + if f.QListener == nil { + return + } + + port := f.QProxyIface.Output[f.Data["name"].Get().(string)].(*engine.Port) + if port.Feature == engine.PortTypeTrigger { + port.Off("call", f.QListener) + } else { + port.Off("value", f.QListener) + } +} + +type fnVarOutputIface struct { + *bpFnVarInOut +} + +func (f *fnVarOutputIface) Imported(data map[string]any) { + f.bpFnVarInOut.Imported(data) + ports := f.QParentFunc.Ref.IOutput + node := f.Node + + node.RefOutput = f.QParentFunc.Ref.Output + + // Create temporary port if the main function doesn't have the port + name := data["name"].(string) + if _, exist := ports[name]; !exist { + iPort := node.CreatePort("input", "Val", types.Any) + proxyIface := f.QParentFunc.QProxyOutput.Iface + + // Run when $this node is being connected with other node + iPort.OnConnect = func(cable *engine.Cable, port *engine.Port) { + iPort.OnConnect = nil + proxyIface.Off("_add."+name, iPort.QWaitPortInit) + iPort.QWaitPortInit = nil + + cable.Disconnect() + node.DeletePort("input", "Val") + + portName := &engine.RefPortName{Name: name} + portType := getFnPortType(port, "output", f.QParentFunc, portName) + newPort := node.CreatePort("input", "Val", portType) + newPort.Name_ = portName + newPort.ConnectPort(port) + + proxyIface.AddPort(port, name) + } + + // Run when main node is the missing port + iPort.QWaitPortInit = func(port *engine.Port) { + iPort.OnConnect = nil + iPort.QWaitPortInit = nil + + backup := []*engine.Port{} + for _, val := range f.Output["Val"].Cables { + backup = append(backup, val.Input) + } + + node := f.Node + node.DeletePort("input", "Val") + + portType := getFnPortType(port, "output", f.QParentFunc, port.Name_) + + newPort := node.CreatePort("input", "Val", portType) + f.QAddListener() + + for _, val := range backup { + newPort.ConnectPort(val) + } + } + + proxyIface.Once("_add."+name, iPort.QWaitPortInit) + } else { + if _, exist := f.Output["Val"]; !exist { + port := ports[name] + portType := getFnPortType(port, "output", f.QParentFunc, port.Name_) + newPort := node.CreatePort("input", "Val", portType) + } + } +} + +func getFnPortType(port *engine.Port, which string, parentNode any, ref *engine.ReferencesShortcut) any { + if port.Feature == engine.PortTypeTrigger { + if which == "input" { // Function Input (has output port inside, and input port on main node) + return types.Function + } else { + return types.Function + } + } else { + if port.Feature != 0 { + if port.Feature == engine.PortTypeArrayOf { + return portTypes.ArrayOf(port.Type) + } else if port.Feature == engine.PortTypeDefault { + return portTypes.Default(port.Type, port.Default) + } else if port.Feature == engine.PortTypeTrigger { + return portTypes.Trigger(port.Func) + } else if port.Feature == engine.PortTypeUnion { + return portTypes.Union(port.Types) + } else if port.Feature == engine.PortTypeStructOf { + return portTypes.StructOf(port.Type, port.Struct) + } else if port.Feature == engine.PortTypeRoute { + return portTypes.Route() + } else { + panic("Port feature was not found for: " + strconv.Itoa(port.Feature)) + } + } else { + return port.Type + } + } +} + +func registerFnVarNode() { + RegisterNode("BP/FnVar/Input", func(i *engine.Instance) any { + node := &fnVarInput{ + Node: &engine.Node{ + Instance: i, + }, + } + + iface := node.SetInterface("BPIC/BP/FnVar/Input").(*fnVarInputIface) + + // Specify data field from here to make it enumerable and exportable + iface.Data = engine.InterfaceData{ + "name": &engine.GetterSetter{Value: ""}, + } + + iface.Title = "FnInput" + iface.Type = "bp-fnvar-input" + iface.QEnum = nodes.BPFnVarInput + iface.QDynamicPort = true + + return node + }) + + RegisterInterface("BPIC/BP/FnVar/Input", func(node any) any { + return &fnVarInputIface{ + bpFnVarInOut: &bpFnVarInOut{ + Interface: &engine.Interface{ + Node: node, + }, + }, + } + }) + + RegisterNode("BP/FnVar/Output", func(i *engine.Instance) any { + node := &fnVarOutput{ + Node: &engine.Node{ + Instance: i, + }, + } + + iface := node.SetInterface("BPIC/BP/FnVar/Output").(*fnVarOutputIface) + + // Specify data field from here to make it enumerable and exportable + iface.Data = engine.InterfaceData{ + "name": &engine.GetterSetter{Value: ""}, + } + + iface.Title = "FnOutput" + iface.Type = "bp-fnvar-output" + iface.QEnum = nodes.BPFnVarOutput + iface.QDynamicPort = true + + return node + }) + + RegisterInterface("BPIC/BP/FnVar/Output", func(node any) any { + return &fnVarOutputIface{ + bpFnVarInOut: &bpFnVarInOut{ + Interface: &engine.Interface{ + Node: node, + }, + }, + } + }) } diff --git a/engine/engine.go b/engine/engine.go index 6196c9c..8266fce 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -18,7 +18,7 @@ type Instance struct { Iface map[string]any // Storing with node id if exist IfaceList map[int]any // Storing with node index settings map[string]bool - QFuncMain *bpFuncMain + QFuncMain // => *engine.Interface } func New() *Instance { diff --git a/engine/interface.go b/engine/interface.go index 5d7ba15..176bcf6 100644 --- a/engine/interface.go +++ b/engine/interface.go @@ -24,7 +24,7 @@ type Interface struct { Data InterfaceData Node any // any = extends *engine.Node - Ref *referencesShortcut + Ref *ReferencesShortcut IsGhost bool Importing bool @@ -48,7 +48,7 @@ var reflectKind = reflect.TypeOf(reflect.Int) // Private (to be called for internal library only) func (iface *Interface) QPrepare() { iface.CustomEvent = &CustomEvent{} - ref := &referencesShortcut{} + ref := &ReferencesShortcut{} node := iface.Node utils.SetProperty(node, "Ref", ref) diff --git a/engine/node.go b/engine/node.go index 411b413..88ed178 100644 --- a/engine/node.go +++ b/engine/node.go @@ -11,9 +11,9 @@ type Node struct { Instance *Instance Iface any // any = extends *engine.Interface DisablePorts bool - Routes RoutePort + Routes *RoutePort - Ref *referencesShortcut + Ref *ReferencesShortcut // Port Template TOutput map[string]any // any = port.Type or *port.Feature diff --git a/engine/references.go b/engine/references.go index 7b66f16..ade6a9c 100644 --- a/engine/references.go +++ b/engine/references.go @@ -1,6 +1,6 @@ package engine -type referencesShortcut struct { +type ReferencesShortcut struct { IInput map[string]*Port Input map[string]*PortInputGetterSetter IOutput map[string]*Port diff --git a/example/example.go b/example/example.go index 082c7e4..ebbd126 100644 --- a/example/example.go +++ b/example/example.go @@ -1,8 +1,8 @@ package example -func RegisterAll() { +func init() { RegisterButton() RegisterDisplay() RegisterInput() RegisterMath() -} \ No newline at end of file +} diff --git a/example/example_test.go b/example/example_test.go index 3e24ba0..3e24be8 100644 --- a/example/example_test.go +++ b/example/example_test.go @@ -17,7 +17,7 @@ func TestMain(m *testing.M) { log.SetFlags(0) // log.SetOutput(ioutil.Discard) - RegisterAll() + // Nodes already be registered from ./example.go -> init() // === Import JSON after all nodes was registered === // You can import the JSON to Blackprint Sketch if you want to view the nodes visually From 92e47d22d0e1475020e6f04e81430de99662ef1b Mon Sep 17 00:00:00 2001 From: Nugraha Date: Wed, 7 Sep 2022 15:18:06 +0700 Subject: [PATCH 04/15] Remove unused `utils/test.go` --- utils/test.go | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 utils/test.go diff --git a/utils/test.go b/utils/test.go deleted file mode 100644 index e629a0e..0000000 --- a/utils/test.go +++ /dev/null @@ -1,35 +0,0 @@ -package utils - -import "fmt" - -type GetterSetter interface { - Set(val any) - Get() any -} - -type MyGetterSetter struct { - val any - aa []*map[string]GetterSetter -} - -func (gs *MyGetterSetter) Set(val any) { - gs.val = val -} - -func (gs *MyGetterSetter) Get() any { - return gs.aa == nil - // return gs.val -} - -func main() { - var aa map[string]GetterSetter - bb := []*map[string]GetterSetter{nil} - - aa = map[string]GetterSetter{ - "Result": &MyGetterSetter{val: 123, aa: bb}, - } - bb[0] = &aa - - aa["Result"].Set("Hello") - fmt.Println(aa["Result"].Get().(bool)) -} From a06cc38a0159501140c2becf5a450200e5561fc5 Mon Sep 17 00:00:00 2001 From: StefansArya Date: Thu, 8 Sep 2022 00:50:34 +0700 Subject: [PATCH 05/15] Add utils for any data types --- blackprint/nodesBPVariable.go | 6 +++--- engine/cable.go | 8 +++---- engine/routePort.go | 4 ++-- utils/utils.go | 39 +++++++++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/blackprint/nodesBPVariable.go b/blackprint/nodesBPVariable.go index 8a9bd68..a9792d1 100644 --- a/blackprint/nodesBPVariable.go +++ b/blackprint/nodesBPVariable.go @@ -106,7 +106,7 @@ func (b *bpVarGetSet) UseType_(port *engine.Port, targetPort *engine.Port) { // Also create port for other node that using $this variable for _, item := range b.QBpVarRef.Used { - utils.CallFunction(item, "QReinitPort", nil) + utils.CallFunction(item, "QReinitPort", utils.EmptyArgs) } } @@ -116,14 +116,14 @@ func (b *bpVarGetSet) Destroy() { return } - utils.RemoveItem(temp.Used, b.Interface) + temp.Used = utils.RemoveItemAny(temp.Used, b) listener := b.QBpVarRef.Listener if listener == nil { return } - utils.RemoveItem(listener, b.Interface) + b.QBpVarRef.Listener = utils.RemoveItemAny(listener, b) } type iVarSet struct { diff --git a/engine/cable.go b/engine/cable.go index 124a8a1..a953568 100644 --- a/engine/cable.go +++ b/engine/cable.go @@ -102,8 +102,8 @@ func (c *Cable) Disconnect(which_ ...*Port) { // which = port c.Input.Out = nil } - c.Output.In = utils.RemoveItem[*Cable](c.Output.In, c) - c.Input.In = utils.RemoveItem[*Cable](c.Input.In, c) + c.Output.In = utils.RemoveItem(c.Output.In, c) + c.Input.In = utils.RemoveItem(c.Input.In, c) c.Connected = false return @@ -118,7 +118,7 @@ func (c *Cable) Disconnect(which_ ...*Port) { // which = port } if c.Owner != nil && (!hasWhich || which == c.Owner) { - utils.RemoveItem[*Cable](c.Owner.Cables, c) + c.Owner.Cables = utils.RemoveItem(c.Owner.Cables, c) if c.Connected { temp := &CableEvent{ @@ -143,7 +143,7 @@ func (c *Cable) Disconnect(which_ ...*Port) { // which = port } if c.Target != nil && c.Connected && (!hasWhich || which == c.Target) { - utils.RemoveItem[*Cable](c.Target.Cables, c) + c.Target.Cables = utils.RemoveItem(c.Target.Cables, c) temp := &CableEvent{ Cable: c, diff --git a/engine/routePort.go b/engine/routePort.go index 80ad5f8..d2c6a3f 100644 --- a/engine/routePort.go +++ b/engine/routePort.go @@ -75,7 +75,7 @@ func (r *RoutePort) RouteIn(cable *Cable) { }) routes := utils.GetProperty(node, "Routes") - utils.CallFunction(routes, "RouteOut", nil) + utils.CallFunction(routes, "RouteOut", utils.EmptyArgs) } func (r *RoutePort) RouteOut() { @@ -87,7 +87,7 @@ func (r *RoutePort) RouteOut() { if utils.GetProperty(r.Iface, "QEnum").(int) == nodes.BPFnOutput { node := utils.GetProperty(utils.GetProperty(r.Iface, "QFuncMain"), "Node") route := utils.GetProperty(node, "Routes").(*RoutePort) - utils.CallFunction(route, "RouteIn", nil) + utils.CallFunction(route, "RouteIn", utils.EmptyArgs) } return diff --git a/utils/utils.go b/utils/utils.go index ab471fe..f9b0772 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -54,6 +54,16 @@ func IndexOf[T comparable](collection []T, el T) int { return -1 } +func IndexOfAny(collection []any, el any) int { + pointer := reflect.ValueOf(el).Pointer() + for i, x := range collection { + if reflect.ValueOf(x).Pointer() == pointer { + return i + } + } + return -1 +} + func Contains[T comparable](collection []T, el T) bool { for _, x := range collection { if x == el { @@ -63,6 +73,16 @@ func Contains[T comparable](collection []T, el T) bool { return false } +func ContainsAny(collection []any, el any) bool { + pointer := reflect.ValueOf(el).Pointer() + for _, x := range collection { + if reflect.ValueOf(x).Pointer() == pointer { + return true + } + } + return false +} + func RemoveItem[T comparable](collection []T, el T) []T { i := IndexOf(collection, el) if i == -1 { @@ -72,6 +92,25 @@ func RemoveItem[T comparable](collection []T, el T) []T { return append(collection[:i], collection[i+1:]...) } +func RemoveItemAny(collection []any, el any) []any { + i := IndexOfAny(collection, el) + if i == -1 { + return collection + } + + return append(collection[:i], collection[i+1:]...) +} + func RemoveItemAtIndex[T comparable](collection []T, i int) []T { return append(collection[:i], collection[i+1:]...) } + +func RemoveItemAtIndexAny(collection []any, i int) []any { + return append(collection[:i], collection[i+1:]...) +} + +func ClearMap[T any](collection map[string]T) { + for key := range collection { + delete(collection, key) + } +} From f683a2fdfeecb6c73c16b35c881436e1aeae1cc2 Mon Sep 17 00:00:00 2001 From: StefansArya Date: Thu, 8 Sep 2022 00:50:59 +0700 Subject: [PATCH 06/15] Some modification for the engine --- engine/bpVar.go | 6 +- engine/engine.go | 382 +++++++++++++++++++++++++++++++++++++------- engine/interface.go | 3 + engine/node.go | 10 +- 4 files changed, 328 insertions(+), 73 deletions(-) diff --git a/engine/bpVar.go b/engine/bpVar.go index 2020cf5..3090e05 100644 --- a/engine/bpVar.go +++ b/engine/bpVar.go @@ -17,7 +17,7 @@ func (b *bpVarValue) Get() any { func (b *bpVarValue) Set(val any) { b.val = val - b.Emit("Value", nil) + b.Emit("value", nil) } // used for instance.CreateVariable @@ -26,9 +26,9 @@ type BPVariable struct { Id string Title string Type reflect.Kind - Used []*Interface + Used []any // *engine.Interface Value bpVarValue - Listener []*Interface + Listener []any // *engine.Interface } func (b *BPVariable) Destroy() { diff --git a/engine/engine.go b/engine/engine.go index 8266fce..ec4fe96 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -5,27 +5,37 @@ import ( "fmt" "reflect" "regexp" + "strings" + "github.com/blackprint/engine-go/engine/nodes" + "github.com/blackprint/engine-go/types" "github.com/blackprint/engine-go/utils" ) var Event = &CustomEvent{} type NodePortTemplate map[string]any - type Instance struct { - CustomEvent - Iface map[string]any // Storing with node id if exist - IfaceList map[int]any // Storing with node index - settings map[string]bool + *CustomEvent + Iface map[string]any // Storing with node id if exist + IfaceList []any // Storing with node index + settings map[string]bool + DisablePorts bool + PanicOnError bool + + Variables map[string]*BPVariable + Functions map[string]*BPFunction + Ref map[string]*ReferencesShortcut + QFuncMain // => *engine.Interface } func New() *Instance { return &Instance{ - Iface: map[string]any{}, - IfaceList: map[int]any{}, - settings: map[string]bool{}, + Iface: map[string]any{}, + IfaceList: map[int]any{}, + settings: map[string]bool{}, + PanicOnError: true, } } @@ -51,14 +61,17 @@ type DataStructure map[Namespace][]NodeX // -type SingleInstanceJSON map[string]nodeList -type metaValue map[string]string +type SingleInstanceJSON map[string]any // any = nodeList | metadataValue +type metadataValue map[string]any type nodeList []nodeConfig type nodeConfig struct { - I int `json:"i"` - Id string `json:"id"` - Data any `json:"data"` - Output map[string][]nodePortTarget `json:"output"` + I int `json:"i"` + Id string `json:"id"` + Data any `json:"data"` + Output map[string][]nodePortTarget `json:"output"` + InputDefault map[string]any `json:"input_d"` + OutputSwitch map[string]uint `json:"output_sw"` + Route map[string]uint `json:"route"` } type nodePortTarget struct { I int `json:"i"` @@ -82,7 +95,11 @@ func (b *GetterSetter) Set(Value any) { b.Value = Value } -func (instance *Instance) ImportJSON(str []byte) (err error) { +type ImportOptions struct { + AppendMode bool +} + +func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inserted []any, err error) { var data SingleInstanceJSON err = json.Unmarshal(str, &data) @@ -90,69 +107,133 @@ func (instance *Instance) ImportJSON(str []byte) (err error) { return } + hasOption := len(options) != 0 + options_ := options[0] + + if hasOption && options_.AppendMode == false { + instance.ClearNodes() + } + + // Do we need this? + // instance.Emit("json.importing", {appendMode: options.appendMode, raw: json}); + ifaceList := instance.IfaceList - var nodes []any + var metadata metadataValue + + appendLength := 0 + if options_.AppendMode { + appendLength = len(ifaceList) + } + + var exist bool + if metadata, exist = data["_"].(metadataValue); exist { + if list, exist := metadata["env"]; exist { + QEnvironment.Import(list.(map[string]string)) + } + + if list, exist := metadata["functions"].(map[string]any); exist { + for key, options := range list { + instance.CreateFunction(key, options) + } + } + + if list, exist := metadata["variables"].(map[string]any); exist { + for key, options := range list { + instance.CreateVariable(key, options) + } + } + + delete(data, "_") + } // Prepare all ifaces based on the namespace // before we create cables for them for namespace, ifaces := range data { - if namespace == "_" { - // meta := ifaces.(metaValue) - continue - } + // Every ifaces that using this namespace name + for _, iface := range ifaces.(nodeList) { + iface.I += appendLength - list := ifaces //.(nodeList) + var temp any + temp, inserted = instance.CreateNode(namespace, iface, inserted) - // Every ifaces that using this namespace name - for _, iface := range list { - ifaceList[iface.I], nodes = instance.CreateNode(namespace, iface, nodes) + ifaceList[iface.I] = temp + utils.CallFunction(temp, "QBpFnInit", utils.EmptyArgs) } } // Create cable only from output and property // > Important to be separated from above, so the cable can reference to loaded ifaces for _, ifaces := range data { - list := ifaces //.(nodeList) + list := ifaces.(nodeList) - for _, iface := range list { - current := ifaceList[iface.I] + for _, ifaceJSON := range list { + iface := ifaceList[ifaceJSON.I] + + if val := ifaceJSON.Route; val != nil { + iface.Node.Routes.RouteTo(ifaceList[val["i"]]) + } // If have output connection - out := iface.Output + out := ifaceJSON.Output if out != nil { - Output := *utils.GetPropertyRef(current, "Output").(*map[string]*Port) + Output := *utils.GetPropertyRef(iface, "Output").(*map[string]*Port) // Every output port that have connection for portName, ports := range out { linkPortA := Output[portName] if linkPortA == nil { - panic(fmt.Sprintf("Node port not found for iface (index: %d), with name: %s", iface.I, portName)) + if iface.QEnum == nodes.BPFnInput { + target := instance.QGetTargetPortType(iface.Node.Instance, "input", ports) + linkPortA = iface.AddPort(target, portName) + + if linkPortA == nil { + panic(fmt.Sprintf("Can't create output port (%s) for function (%s)", portName, iface.QFuncMain.Node.QFuncInstance.Id)) + } + } else if iface.QEnum == nodes.BPVarGet { + target := instance.QGetTargetPortType(instance, "input", ports) + iface.UseType(target) + linkPortA = iface.Output[portName] + } else { + panic(fmt.Sprintf("Node port not found for iface (index: %d), with name: %s", ifaceJSON.I, portName)) + } } // Current output's available targets for _, target := range ports { + target.I += appendLength targetNode := ifaceList[target.I] + // output can only meet input port Input := *utils.GetPropertyRef(targetNode, "Input").(*map[string]*Port) linkPortB := Input[target.Name] if linkPortB == nil { targetTitle := utils.GetProperty(targetNode, "Title").(string) - panic(fmt.Sprintf("Node port not found for %s with name: %s", targetTitle, target.Name)) + + if targetNode.QEnum == nodes.BPFnOutput { + linkPortB = targetNode.AddPort(linkPortA, target) + + if linkPortB == nil { + panic(fmt.Sprintf("Can't create output port (%s) for function (%s)", portName, targetNode.QFuncMain.Node.QFuncInstance.Id)) + } + } else if targetNode.QEnum == nodes.BPVarGet { + targetNode.UseType(target) + linkPortB = targetNode.Input[target.Name] + } else if targetNode.Type == types.Route { + linkPortB = targetNode.Node.Routes + } else { + panic(fmt.Sprintf("Node port not found for %s with name: %s", targetTitle, target.Name)) + } } // For Debugging -> - // Title := utils.GetProperty(current, "Title").(string) + // Title := utils.GetProperty(iface, "Title").(string) // targetTitle := utils.GetProperty(targetNode, "Title").(string) // fmt.Printf("%s.%s => %s.%s\n", Title, linkPortA.Name, targetTitle, linkPortB.Name) // <- For Debugging - cable := NewCable(linkPortA, linkPortB) - linkPortA.Cables = append(linkPortA.Cables, cable) - linkPortB.Cables = append(linkPortB.Cables, cable) - - cable.QConnected() + linkPortA.ConnectPort(linkPortB) // fmt.Println(cable.String()) } } @@ -161,12 +242,80 @@ func (instance *Instance) ImportJSON(str []byte) (err error) { } // Call nodes init after creation processes was finished - for _, val := range nodes { + for _, val := range inserted { utils.CallFunction(val, "Init", utils.EmptyArgs) } + return } +func (instance *Instance) QGetTargetPortType(ins *Instance, which string, targetNodes []nodePortTarget) *Port { + target := targetNodes[0] // ToDo: check all target in case if it's supporting Union type + targetIface := ins.IfaceList[target.I] + + if which == "input" { + return targetIface.Input[target.Name] + } else { + return targetIface.Output[target.Name] + } +} + +type EvNodeDelete struct { + Iface any +} + +func (instance *Instance) DeleteNode(iface any) { + i := utils.IndexOfAny(instance.IfaceList, iface) + if i == -1 { + panic("Node to be deleted was not found") + } + + instance.IfaceList = utils.RemoveItemAtIndexAny(instance.IfaceList, i) + + eventData := &EvNodeDelete{ + Iface: iface, + } + instance.Emit("node.delete", eventData) + + iface.Node.Destroy() + iface.Destroy() + + for _, port := range iface.Output { + port.DisconnectAll(instance.QRemote == nil) + } + + routes := iface.Node.Routes + for _, cable := range routes.In { + cable.Disconnect() + } + + if routes.Out != nil { + routes.Out.Disconnect() + } + + // Delete reference + delete(instance.Iface, iface.Id) + delete(instance.Ref, iface.Id) + + parent := iface.Node.Instance.QFuncMain + if parent != nil { + delete(parent.Ref, iface.Id) + } + + instance.Emit("node.deleted", eventData) +} + +func (instance *Instance) ClearNodes() { + for _, iface := range instance.IfaceList { + iface.Node.Destroy() + iface.Destroy() + } + + instance.IfaceList = instance.IfaceList[:0] + utils.ClearMap(instance.Iface) + utils.ClearMap(instance.Ref) +} + func (instance *Instance) Settings(id string, val ...bool) bool { if val == nil { return instance.settings[id] @@ -199,14 +348,33 @@ func (instance *Instance) GetNodes(namespace string) []any { return got } +// ToDo: sync with JS, when creating function node this still broken func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes []any) (any, []any) { func_ := QNodeList[namespace] + var node any // *node: extends engine.Node + var isFuncNode bool if func_ == nil { - panic("Node nodes for " + namespace + " was not found, maybe .registerNode() haven't being called?") + if strings.HasPrefix(namespace, "BPI/F/") { + temp := instance.Functions[namespace] + if temp != nil { + node = temp.QBuilder() + } + + isFuncNode = true + } + + if node == nil { + panic("Node nodes for " + namespace + " was not found, maybe .registerNode() haven't being called?") + } + } else { + node = func_(instance) // func_ from registerNode(namespace, func_) + } + + // Disable data flow on any node ports + if instance.DisablePorts { + node.DisablePorts = true } - // *node: extends engine.Node - node := func_(instance) // func_ from registerNode(namespace, func_) if utils.IsPointer(node) == false { panic(namespace + ": .registerNode() must return pointer") } @@ -218,56 +386,148 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes } utils.SetProperty(iface, "Node", node) - - // Assign the saved options if exist - // Must be called here to avoid port trigger - if options.Data != nil { - data := utils.GetPropertyRef(iface, "Data").(*InterfaceData) - if data != nil { - deepMerge(data, options.Data.(map[string]any)) - } - } - utils.SetProperty(iface, "Namespace", namespace) // Create the linker between the nodes and the iface - utils.CallFunction(iface, "QPrepare", utils.EmptyArgs) + if isFuncNode == false { + utils.CallFunction(iface, "QPrepare", utils.EmptyArgs) + } if options.Id != "" { utils.SetProperty(iface, "Id", options.Id) instance.Iface[options.Id] = iface + instance.Ref[options.Id] = iface.Ref + + parent := iface.Node.Instance.QFuncMain + if parent != nil { + parent.Ref[options.Id] = iface.Ref + } } utils.SetProperty(iface, "I", options.I) instance.IfaceList[options.I] = iface + if options.InputDefault != nil { + iface.QImportInputs(options.InputDefault) + } + + savedData := &[]reflect.Value{reflect.ValueOf(options.Data)} + + if options.OutputSwitch != nil { + for key, val := range options.OutputSwitch { + if (val | 1) == 1 { + portStructOf_split(iface.Output[key]) + } + + if (val | 2) == 2 { + iface.Output[key].AllowResync = true + } + } + } + utils.SetProperty(iface, "Importing", false) - utils.CallFunction(node, "Imported", utils.EmptyArgs) + utils.CallFunction(iface, "Imported", savedData) + utils.CallFunction(node, "Imported", savedData) + + utils.CallFunction(iface, "Init", utils.EmptyArgs) if nodes != nil { nodes = append(nodes, node) + } else { + // Init now if not A batch creation + utils.CallFunction(node, "Init", utils.EmptyArgs) } - utils.CallFunction(node, "Init", utils.EmptyArgs) - utils.CallFunction(iface, "Init", utils.EmptyArgs) - return iface, nodes } var createBPVariableRegx = regexp.MustCompile(`[` + "`" + `~!@#$%^&*()\-_+={}\[\]:"|;\'\\\\,.\/<>?]+`) -func (instance *Instance) CreateVariable(id string) *BPVariable { - return &BPVariable{ +type varOptions struct { + Id string `json:"id"` + Title string `json:"title"` +} + +func (instance *Instance) CreateVariable(id string, options any) *BPVariable { + if old, exist := instance.Variables[id]; exist { + old.Destroy() + delete(instance.Variables, id) + } + + // options_ = options.(varOptions) + + temp := &BPVariable{ + Id: id, + Title: id, + Type: 0, // Type not set + } + instance.Variables[id] = temp + instance.Emit("variable.new", temp) + + return temp +} + +type funcOptions struct { + Id string `json:"id"` + Title string `json:"title"` + Vars []string `json:"vars"` + PrivateVars []string `json:"privateVars"` + Structure nodeList `json:"structure"` +} + +func (instance *Instance) CreateFunction(id string, options any) *BPFunction { + if old, exist := instance.Functions[id]; exist { + old.Destroy() + delete(instance.Functions, id) + } + + temp := &BPFunction{ Id: id, Title: id, Type: 0, // Type not set } + instance.Functions[id] = temp + + options_ := options.(funcOptions) + + for _, val := range options_.Vars { + temp.CreateVariable(val, bpFnVarOptions{ + Scope: val, + }) + } + + for _, val := range options_.PrivateVars { + temp.AddPrivateVars(val) + } + + instance.Emit("function.new", temp) + return temp +} + +type NodeLogEvent struct { + Instance *Instance + Iface any + IfaceTitle string + Message string +} + +func (instance *Instance) QLog(iface any, message string) { + evData := NodeLogEvent{ + Instance: instance, + Iface: iface, + IfaceTitle: utils.GetProperty(iface, "Title").(string), + Message: message, + } - // The type need to be defined dynamically on first cable connect + if instance.QMainInstance != nil { + instance.QMainInstance.Emit("log", evData) + } else { + instance.Emit("log", evData) + } } -func (instance *Instance) QLog(event NodeLog) { - fmt.Println(utils.GetProperty(event.Iface, "Title").(string) + "> " + event.Message) +func (instance *Instance) Destroy() { + instance.ClearNodes() } // Currently only one level diff --git a/engine/interface.go b/engine/interface.go index 176bcf6..c806900 100644 --- a/engine/interface.go +++ b/engine/interface.go @@ -43,6 +43,9 @@ func (iface *Interface) Init() {} func (iface *Interface) Destroy() {} func (iface *Interface) Imported(data any) {} +// Internal blackprint function node initialization +func (iface *Interface) QBpFnInit() {} + var reflectKind = reflect.TypeOf(reflect.Int) // Private (to be called for internal library only) diff --git a/engine/node.go b/engine/node.go index 88ed178..1b4b267 100644 --- a/engine/node.go +++ b/engine/node.go @@ -156,16 +156,8 @@ func (n *Node) DeletePort(which string, name string) { delete(ports, name) } -type NodeLog struct { - Iface any - Message string -} - func (n *Node) Log(message string) { - n.Instance.QLog(NodeLog{ - Iface: n.Iface, - Message: message, - }) + n.Instance.QLog(n.Iface, message) } // To be overriden by module developer From 97d8b768c9517d32bb1bb5418cbe4911aa1f6d78 Mon Sep 17 00:00:00 2001 From: StefansArya Date: Thu, 8 Sep 2022 16:29:54 +0700 Subject: [PATCH 07/15] Adapt port implementation and do some changes --- blackprint/nodesBPVariable.go | 3 +- blackprint/nodesFnPortVar.go | 23 +-- engine/cable.go | 10 +- engine/engine.go | 2 +- engine/interface.go | 23 ++- engine/port.go | 372 +++++++++++++++++++++------------- engine/portGetterSetter.go | 188 +++++++++++++++++ engine/portTypes.go | 74 +++++++ example/logger.go | 3 +- example/math.go | 19 +- port/types.go | 68 ------- 11 files changed, 521 insertions(+), 264 deletions(-) create mode 100644 engine/portGetterSetter.go create mode 100644 engine/portTypes.go delete mode 100644 port/types.go diff --git a/blackprint/nodesBPVariable.go b/blackprint/nodesBPVariable.go index a9792d1..1e8bb71 100644 --- a/blackprint/nodesBPVariable.go +++ b/blackprint/nodesBPVariable.go @@ -6,7 +6,6 @@ import ( "github.com/blackprint/engine-go/engine" "github.com/blackprint/engine-go/engine/nodes" - "github.com/blackprint/engine-go/port" "github.com/blackprint/engine-go/types" "github.com/blackprint/engine-go/utils" ) @@ -237,7 +236,7 @@ func (b *iVarGet) QReinitPort() *engine.Port { utils.CallFunction(node, "CreatePort", &[]reflect.Value{ reflect.ValueOf("Input"), reflect.ValueOf("Val"), - reflect.ValueOf(port.Trigger(func(p *engine.Port) { + reflect.ValueOf(engine.Ports.Trigger(func(p *engine.Port) { temp.Emit("call", nil) })), }) diff --git a/blackprint/nodesFnPortVar.go b/blackprint/nodesFnPortVar.go index c0dfa00..40fa9d3 100644 --- a/blackprint/nodesFnPortVar.go +++ b/blackprint/nodesFnPortVar.go @@ -1,11 +1,8 @@ package blackprint import ( - "strconv" - "github.com/blackprint/engine-go/engine" "github.com/blackprint/engine-go/engine/nodes" - portTypes "github.com/blackprint/engine-go/port" "github.com/blackprint/engine-go/types" ) @@ -238,30 +235,16 @@ func (f *fnVarOutputIface) Imported(data map[string]any) { } } -func getFnPortType(port *engine.Port, which string, parentNode any, ref *engine.ReferencesShortcut) any { +func getFnPortType(port *engine.Port, which string, parentNode any, ref *engine.RefPortName) any { if port.Feature == engine.PortTypeTrigger { if which == "input" { // Function Input (has output port inside, and input port on main node) return types.Function } else { - return types.Function + return engine.Ports.Trigger(parentNode.Output[ref.Name].CallAll) } } else { if port.Feature != 0 { - if port.Feature == engine.PortTypeArrayOf { - return portTypes.ArrayOf(port.Type) - } else if port.Feature == engine.PortTypeDefault { - return portTypes.Default(port.Type, port.Default) - } else if port.Feature == engine.PortTypeTrigger { - return portTypes.Trigger(port.Func) - } else if port.Feature == engine.PortTypeUnion { - return portTypes.Union(port.Types) - } else if port.Feature == engine.PortTypeStructOf { - return portTypes.StructOf(port.Type, port.Struct) - } else if port.Feature == engine.PortTypeRoute { - return portTypes.Route() - } else { - panic("Port feature was not found for: " + strconv.Itoa(port.Feature)) - } + return port.QGetPortFeature() } else { return port.Type } diff --git a/engine/cable.go b/engine/cable.go index a953568..55a241f 100644 --- a/engine/cable.go +++ b/engine/cable.go @@ -12,7 +12,8 @@ type Cable struct { Target *Port Input *Port Output *Port - Disabled bool + Source int + Disabled int IsRoute bool Connected bool QEvDisconnected bool @@ -24,9 +25,7 @@ type CableEvent struct { Target *Port } -type PortSelfEvent struct { - Port *Port -} +type PortValueEvent = CableEvent func NewCable(owner *Port, target *Port) *Cable { var input *Port @@ -42,6 +41,7 @@ func NewCable(owner *Port, target *Port) *Cable { return &Cable{ Type: owner.Type, + Source: owner.Source, Owner: owner, Target: target, Input: input, @@ -72,7 +72,7 @@ func (c *Cable) QConnected() { return } - inputEv := &PortSelfEvent{ + inputEv := &PortValueEvent{ Port: c.Output, } c.Input.Emit("value", inputEv) diff --git a/engine/engine.go b/engine/engine.go index ec4fe96..f13ee8c 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -382,7 +382,7 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes // *iface: extends engine.Interface iface := utils.GetProperty(node, "Iface") if iface == nil || utils.GetProperty(iface, "QInitialized").(bool) == false { - panic(namespace + ": Node interface was not found, do you forget to call node->setInterface() ?") + panic(namespace + ": Node interface was not found, do you forget to call node.SetInterface() ?") } utils.SetProperty(iface, "Node", node) diff --git a/engine/interface.go b/engine/interface.go index c806900..39d1f8a 100644 --- a/engine/interface.go +++ b/engine/interface.go @@ -109,6 +109,7 @@ func (iface *Interface) QCreatePort(which string, name string, config_ any) *Por var feature int var def any + var qfunc func(*Port) if reflect.TypeOf(config_) == reflectKind { type_ = config_.(reflect.Kind) @@ -135,7 +136,7 @@ func (iface *Interface) QCreatePort(which string, name string, config_ any) *Por feature = config.Id if feature == PortTypeTrigger { - def = config.Func + qfunc = config.Func type_ = types.Function } else if feature == PortTypeArrayOf { if type_ != types.Any { @@ -160,15 +161,19 @@ func (iface *Interface) QCreatePort(which string, name string, config_ any) *Por // source = PortProperty // } - return &Port{ - Name: name, - Type: type_, - Types: types_, - Default: def, - Source: source, - Iface: iface, - Feature: feature, + port := &Port{ + Name: name, + Type: type_, + Types: types_, + Default: def, + QFunc: qfunc, + Source: source, + Iface: iface, + Feature: feature, + QFeature: config, } + + return port } func (iface *Interface) QInitPortSwitches(portSwitches map[string]int) { diff --git a/engine/port.go b/engine/port.go index 38702c1..f5bbc9e 100644 --- a/engine/port.go +++ b/engine/port.go @@ -3,6 +3,8 @@ package engine import ( "reflect" + "github.com/blackprint/engine-go/engine/nodes" + "github.com/blackprint/engine-go/types" "github.com/blackprint/engine-go/utils" ) @@ -23,12 +25,12 @@ type Port struct { Iface any Default any // Dynamic data (depend on Type) for storing port value (int, string, map, etc..) Value any // Dynamic data (depend on Type) for storing port value (int, string, map, etc..) - Func func(*Port) Sync bool Feature int + QFeature *PortFeature // For caching the configuration Struct map[string]PortStructTemplate Splitted bool - AllowResync bool + AllowResync bool // Retrigger connected node's .update when the output value is similar // Only in Golang we need to do this '-' RoutePort *RoutePort @@ -37,6 +39,10 @@ type Port struct { QCache any QParent *Port QStructSplitted bool + QGhost bool + QFunc func(*Port) + QCallAll func() + OnConnect func(*Cable, *Port) } type RefPortName struct { @@ -64,198 +70,282 @@ type PortFeature struct { Type reflect.Kind Types []reflect.Kind Value any - Func any + Func func(*Port) } -type PortInputGetterSetter struct { - getterSetter - port *Port -} - -func (gs *PortInputGetterSetter) Set(val any) { - panic("Can't set input port's value") +func (port *Port) QGetPortFeature() *PortFeature { + return port.QFeature } +func (port *Port) DisconnectAll(hasRemote bool) { + for _, cable := range port.Cables { + if hasRemote { + cable.QEvDisconnected = true + } -func (gs *PortInputGetterSetter) Call() { - gs.port.Default.(func(*Port))(gs.port) + cable.Disconnect() + } } -func (gs *PortInputGetterSetter) Get() any { - port := gs.port +// ./portGetterSetter.go +func (port *Port) CreateLinker() getterSetter { + if port.Source == PortInput { + return &PortInputGetterSetter{port: port} + } - // This port must use values from connected output - cableLen := len(port.Cables) + return &PortOutputGetterSetter{port: port} +} - if cableLen == 0 { - if port.Feature == PortTypeArrayOf { - // ToDo: fix type to follow - // the type from port.Type +func (port *Port) sync() { + var target *Port + skipSync := port.Iface.Node.Routes.Out != nil - return [](any){} + for _, cable := range port.Cables { + inp := cable.Input + if inp == nil { + continue } - return port.Default - } - - // Flag current iface is requesting value to other iface + inp.QCache = nil - // Return single data - if cableLen == 1 { - temp := port.Cables[0] - var target *Port - - if temp.Owner == port { - target = temp.Target - } else { - target = temp.Owner + temp := &PortValueEvent{ + Target: inp, + Port: port, + Cable: cable, } + inpIface := inp.Iface + + inp.Emit("value", temp) + inpIface.Emit("value", temp) - if target.Value == nil { - port.Iface.QRequesting = true - utils.CallFunction(target.Iface.Node, "Request", &[]reflect.Value{ - reflect.ValueOf(target), - reflect.ValueOf(port.Iface), - }) - port.Iface.QRequesting = false + if skipSync { + continue } - // fmt.Printf("1. %s -> %s (%s)\n", port.Name, target.Name, target.Value) + node := inpIface.Node + if inpIface.QRequesting == false && len(node.Routes.In) == 0 { + node.Update(cable) - if port.Feature == PortTypeArrayOf { - var tempVal any - if target.Value == nil { - tempVal = target.Default + if inpIface.QEnum == nodes.BPFnMain { + node.Routes.RouteOut() } else { - tempVal = target.Value + inpIface.QProxyInput.Routes.RouteOut() } - - return [](any){tempVal} - } - - if target.Value == nil { - return target.Default - } else { - return target.Value } } +} - // Return multiple data as an array - data := []any{} - for _, cable := range port.Cables { - var target *Port - if cable.Owner == port { - target = cable.Target - } else { - target = cable.Owner +func (port *Port) DisableCables(enable bool) { + if enable { + for _, cable := range port.Cables { + cable.Disabled = 1 } - - if target.Value == nil { - port.Iface.QRequesting = true - utils.CallFunction(target.Iface.Node, "Request", &[]reflect.Value{ - reflect.ValueOf(target), - reflect.ValueOf(port.Iface), - }) - port.Iface.QRequesting = false + } else if !enable { + for _, cable := range port.Cables { + cable.Disabled = 0 } + } else { + panic("Unhandled, please check engine-php's implementation") + } +} - // fmt.Printf("2. %s -> %s (%s)\n", port.Name, target.Name, target.Value) +type CableErrorEvent struct { + Cable *Cable + OldCable *Cable + Iface *Interface + Port *Port + Target *Port + Message string +} - if target.Value == nil { - data = append(data, target.Default) - } else { - data = append(data, target.Value) - } +func (port *Port) QCableConnectError(name string, obj *CableErrorEvent, severe bool) { + msg := "Cable notify: " + name + if obj.Iface != nil { + msg += "\nIFace: " + obj.Iface.Namespace } - if port.Feature != PortTypeArrayOf { - return data[0] + if obj.Port != nil { + msg += "\nFrom port: " + obj.Port.Name + ") (iface: " + obj.Port.Iface.Namespace + ")\n - Type: " + obj.Port.Source + ") (" + obj.Port.Type + ")" } - return data -} + if obj.Target { + msg += "\nTo port: " + obj.Target.Name + ") (iface: " + obj.Target.Iface.Namespace + "))\n - Type: " + obj.Target.Source + ") (" + obj.Target.Type + "))" + } + + obj.Message = msg + instance := port.Iface.Node.Instance -type PortOutputGetterSetter struct { - getterSetter - port *Port + if severe && instance.PanicOnError { + panic(msg + "\n\n") + } + + instance.emit(name, obj) } +func (port *Port) ConnectCable(cable *Cable) bool { + if cable.IsRoute { + port.QCableConnectError("cable.not_route_port", &CableErrorEvent{ + Cable: cable, + Port: port, + Target: cable.Owner, + }, true) + + cable.Disconnect() + return false + } -func (gs *PortOutputGetterSetter) Set(val any) { - port := gs.port + if cable.Owner == port { // It's referencing to same port + cable.Disconnect() + return false + } - if port.Source == PortInput { - panic("Can't set data to input port") + if (port.OnConnect != nil && port.OnConnect(cable, cable.Owner)) || (cable.Owner.OnConnect != nil && cable.Owner.OnConnect(cable, port)) { + return false } - // ToDo: do we need feature validation here? - // fmt.Printf("3. %s = %s\n", port.Name, val) + // Remove cable if ... + if (cable.Source == PortOutput && port.Source != PortInput) /* Output source not connected to input */ || (cable.Source == PortInput && port.Source != PortOutput) /* Input source not connected to output */ { + port.QCableConnectError("cable.wrong_pair", &CableErrorEvent{ + Cable: cable, + Port: port, + Target: cable.Owner, + }, true) - port.Value = val - port.Emit("value", &PortSelfEvent{ - Port: port, - }) - port.sync() -} + cable.Disconnect() + return false + } -func (gs *PortOutputGetterSetter) Call() { - var target *Port - for _, cable := range gs.port.Cables { - if cable.Owner == gs.port { - target = cable.Target - } else { - target = cable.Owner + if cable.Owner.Source == PortOutput { + if (port.Feature == PortTypeArrayOf && !portArrayOf_validate(port, cable.Owner)) || (port.Feature == PortTypeUnion && !portUnion_validate(port, cable.Owner)) { + port.QCableConnectError("cable.wrong_type", &CableErrorEvent{ + Cable: cable, + Iface: port.Iface, + Port: cable.Owner, + Target: port, + }, true) + + cable.Disconnect() + return false } + } else if port.Source == PortOutput { + if (cable.Owner.Feature == PortTypeArrayOf && !portArrayOf_validate(cable.Owner, port)) || (cable.Owner.Feature == PortTypeUnion && !portUnion_validate(cable.Owner, port)) { + port.QCableConnectError("cable.wrong_type", &CableErrorEvent{ + Cable: cable, + Iface: port.Iface, + Port: port, + Target: cable.Owner, + }, true) + + cable.Disconnect() + return false + } + } - // fmt.Println(cable.String()) - target.Default.(func(*Port))(target) + // Golang can't check by class instance or inheritance + // ========================================== + // ToDo: recheck why we need to check if the constructor is a function + // isInstance = true; + // if cable.Owner.Type != port.Type && cable.Owner.Type == types.Function && port.Type == types.Function { + // if cable.Owner.Source == PortOutput{ + // isInstance = cable.Owner.Type instanceof port.Type + // } else { + // isInstance = port.Type instanceof cable.Owner.Type + // } + // } + // ========================================== + + // Remove cable if type restriction + // if !isInstance || (cable.Owner.Type == types.Function && port.Type != types.Function || cable.Owner.Type != types.Function && port.Type == types.Function) { + if cable.Owner.Type == types.Function && port.Type != types.Function || cable.Owner.Type != types.Function && port.Type == types.Function { + port.QCableConnectError("cable.wrong_type_pair", &CableErrorEvent{ + Cable: cable, + Port: port, + Target: cable.Owner, + }, true) + + cable.Disconnect() + return false } -} -func (gs *PortOutputGetterSetter) Get() any { - port := gs.port + // Restrict connection between function input/output node with variable node + // Connection to similar node function IO or variable node also restricted + // These port is created on runtime dynamically + if port.Iface.QDynamicPort && cable.Owner.Iface.QDynamicPort { + port.QCableConnectError("cable.unsupported_dynamic_port", &CableErrorEvent{ + Cable: cable, + Port: port, + Target: cable.Owner, + }, true) + + cable.Disconnect() + return false + } - if port.Feature == PortTypeArrayOf { - var tempVal any - if port.Value == nil { - tempVal = port.Default - } else { - tempVal = port.Value + // Remove cable if there are similar connection for the ports + for _, cable := range cable.Owner.Cables { + if utils.Contains(port.Cables, cable) { + port.QCableConnectError("cable.duplicate_removed", &CableErrorEvent{ + Cable: cable, + Port: port, + Target: cable.Owner, + }, false) + + cable.Disconnect() + return false } - - return [](any){tempVal} } - if port.Value == nil { - return port.Default + // Put port reference to the cable + cable.Target = port + + var inp *Port + var out *Port + if cable.Target.Source == PortInput { + /** @var Port */ + inp = cable.Target + out = cable.Owner + } else { + /** @var Port */ + inp = cable.Owner + out = cable.Target } - return port.Value -} + // Remove old cable if the port not support array + if inp.Feature != PortTypeArrayOf && inp.Type != types.Function { + cables := inp.Cables // Cables in input port -func (port *Port) CreateLinker() getterSetter { - if port.Source == PortInput { - return &PortInputGetterSetter{port: port} - } + if len(cables) != 0 { + temp := cables[0] - return &PortOutputGetterSetter{port: port} -} + if temp == cable { + temp = cables[1] + } -func (port *Port) sync() { - var target *Port - for _, cable := range port.Cables { - if cable.Owner == port { - target = cable.Target - } else { - target = cable.Owner - } + if temp != nil { + inp.QCableConnectError("cable.replaced", &CableErrorEvent{ + Cable: cable, + OldCable: temp, + Port: inp, + Target: out, + }, false) - if target.Iface.QRequesting == false { - utils.CallFunction(target.Iface.Node, "Update", &[]reflect.Value{ - reflect.ValueOf(cable), - }) + temp.Disconnect() + return false + } } + } - target.Emit("value", &PortSelfEvent{ - Port: port, - }) + // Connect this cable into port's cable list + port.Cables = append(port.Cables, cable) + // cable.Connecting(); + cable.QConnected() + + return true +} +func (port *Port) ConnectPort(portTarget *Port) bool { + cable := NewCable(portTarget, port) + if portTarget.QGhost { + cable.QGhost = true } + + portTarget.Cables = append(portTarget.Cables, cable) + return port.ConnectCable(cable) } diff --git a/engine/portGetterSetter.go b/engine/portGetterSetter.go new file mode 100644 index 0000000..60fcf71 --- /dev/null +++ b/engine/portGetterSetter.go @@ -0,0 +1,188 @@ +package engine + +import ( + "reflect" + + "github.com/blackprint/engine-go/types" + "github.com/blackprint/engine-go/utils" +) + +type PortInputGetterSetter struct { + getterSetter + port *Port +} + +func (gs *PortInputGetterSetter) Set(val any) { + panic("Can't set input port's value") +} + +func (gs *PortInputGetterSetter) Call() { + gs.port.QFunc(gs.port) + gs.port.Iface.Node.Routes.RouteOut() +} + +func (gs *PortInputGetterSetter) Get() any { + port := gs.port + + // This port must use values from connected output + cableLen := len(port.Cables) + + if cableLen == 0 { + if port.Feature == PortTypeArrayOf { + // ToDo: fix type to follow + // the type from port.Type + + return [](any){} + } + + return port.Default + } + + // Flag current iface is requesting value to other iface + + // Return single data + if cableLen == 1 { + temp := port.Cables[0] + var target *Port + + if temp.Owner == port { + target = temp.Target + } else { + target = temp.Owner + } + + if target.Value == nil { + port.Iface.QRequesting = true + utils.CallFunction(target.Iface.Node, "Request", &[]reflect.Value{ + reflect.ValueOf(target), + reflect.ValueOf(port.Iface), + }) + port.Iface.QRequesting = false + } + + // fmt.Printf("1. %s -> %s (%s)\n", port.Name, target.Name, target.Value) + + if port.Feature == PortTypeArrayOf { + var tempVal any + if target.Value == nil { + tempVal = target.Default + } else { + tempVal = target.Value + } + + return [](any){tempVal} + } + + if target.Value == nil { + return target.Default + } else { + return target.Value + } + } + + // Return multiple data as an array + data := []any{} + for _, cable := range port.Cables { + var target *Port + if cable.Owner == port { + target = cable.Target + } else { + target = cable.Owner + } + + if target.Value == nil { + port.Iface.QRequesting = true + utils.CallFunction(target.Iface.Node, "Request", &[]reflect.Value{ + reflect.ValueOf(target), + reflect.ValueOf(port.Iface), + }) + port.Iface.QRequesting = false + } + + // fmt.Printf("2. %s -> %s (%s)\n", port.Name, target.Name, target.Value) + + if target.Value == nil { + data = append(data, target.Default) + } else { + data = append(data, target.Value) + } + } + + if port.Feature != PortTypeArrayOf { + return data[0] + } + + return data +} + +type PortOutputGetterSetter struct { + getterSetter + port *Port +} + +func (gs *PortOutputGetterSetter) Set(val any) { + port := gs.port + + if port.Source == PortInput { + panic("Can't set data to input port") + } + + // ToDo: do we need feature validation here? + // fmt.Printf("3. %s = %s\n", port.Name, val) + + port.Value = val + port.Emit("value", &PortValueEvent{ + Port: port, + }) + port.sync() +} + +// createCallablePort +// createCallableRoutePort +func (gs *PortOutputGetterSetter) Call() { + if gs.port.Type == types.Route { + cable := gs.port.Cables[0] + if cable == nil { + return + } + + cable.Input.RoutePort.RouteIn(cable) + } else { + for _, cable := range gs.port.Cables { + target := cable.Input + if target == nil { + continue + } + + // fmt.Println(cable.String()) + if target.QName != nil { + target.Iface.QParentFunc.node.Output[target.QName.Name].Call() + } else { + target.Iface.Node.Input[target.Name].Call() + } + } + + gs.port.Emit("call", nil) + } +} + +func (gs *PortOutputGetterSetter) Get() any { + port := gs.port + + if port.Feature == PortTypeArrayOf { + var tempVal any + if port.Value == nil { + tempVal = port.Default + } else { + tempVal = port.Value + } + + return [](any){tempVal} + } + + if port.Value == nil { + return port.Default + } + + return port.Value +} diff --git a/engine/portTypes.go b/engine/portTypes.go new file mode 100644 index 0000000..d9cbfd9 --- /dev/null +++ b/engine/portTypes.go @@ -0,0 +1,74 @@ +package engine + +import ( + "reflect" +) + +type portObject struct{} + +var Ports *portObject + +func init() { + Ports = &portObject{} +} + +/* This port can contain multiple cable as input + * and the value will be array of 'type' + * it's only one type, not union + * for union port, please split it to different port to handle it + */ +func (*portObject) ArrayOf(type_ reflect.Kind) *PortFeature { + return &PortFeature{ + Id: PortTypeArrayOf, + Type: type_, + } +} + +/* This port can have default value if no cable was connected + * type = Type Data that allowed for the Port + * value = default value for the port + */ +func (*portObject) Default(type_ reflect.Kind, val any) *PortFeature { + return &PortFeature{ + Id: PortTypeDefault, + Type: type_, + Value: val, + } +} + +/* This port will be used as a trigger or callable input port + * func (*portObject) = callback when the port was being called as a function + */ +func (*portObject) Trigger(callback func(*Port)) *PortFeature { + return &PortFeature{ + Id: PortTypeTrigger, + Func: callback, + } +} + +/* This port can allow multiple different types + * like an 'any' port, but can only contain one value + */ +func (*portObject) Union(types []reflect.Kind) *PortFeature { + return &PortFeature{ + Id: PortTypeUnion, + Types: types, + } +} + +/* This port can allow multiple different types + * like an 'any' port, but can only contain one value + */ +func (*portObject) StructOf(type_ reflect.Kind, structure map[string]PortStructTemplate) *PortFeature { + return &PortFeature{ + Id: PortTypeStructOf, + Type: type_, + Value: structure, + } +} + +func (*portObject) Route() *PortFeature { + return &PortFeature{ + Id: PortTypeRoute, + } +} diff --git a/example/logger.go b/example/logger.go index 32739e9..cd28dbc 100644 --- a/example/logger.go +++ b/example/logger.go @@ -7,7 +7,6 @@ import ( Blackprint "github.com/blackprint/engine-go/blackprint" "github.com/blackprint/engine-go/engine" - "github.com/blackprint/engine-go/port" ) // This will be called from example.go @@ -77,7 +76,7 @@ func RegisterLogger() { // Node's Input Port Template TInput: engine.NodePortTemplate{ - "Any": port.ArrayOf(reflect.Interface), // nil => Any + "Any": engine.Ports.ArrayOf(reflect.Interface), // nil => Any }, }, } diff --git a/example/math.go b/example/math.go index f788335..6bff003 100644 --- a/example/math.go +++ b/example/math.go @@ -4,12 +4,9 @@ import ( "crypto/rand" "encoding/binary" "log" - "reflect" - "strconv" Blackprint "github.com/blackprint/engine-go/blackprint" "github.com/blackprint/engine-go/engine" - "github.com/blackprint/engine-go/port" "github.com/blackprint/engine-go/types" ) @@ -45,22 +42,12 @@ func RegisterMathMultiply() { // Node's Input Port Template TInput: engine.NodePortTemplate{ - "Exec": port.Trigger(func(port *engine.Port) { + "Exec": engine.Ports.Trigger(func(port *engine.Port) { node.Output["Result"].Set(node.Multiply()) log.Printf("\x1b[1m\x1b[33mMath\\Multiply:\x1b[0m \x1b[33mResult has been set: %d\x1b[0m\n", node.Output["Result"].Get()) }), "A": types.Int, - "B": port.Validator(types.Int, func(val any) any { - log.Printf("\x1b[1m\x1b[33mMath\\Multiply:\x1b[0m \x1b[33m%s - Port B got input: %d\x1b[0m\n", node.Iface.(*engine.Interface).Title, val) - - // Convert string to number - if reflect.ValueOf(val).Kind() == reflect.String { - num, _ := strconv.Atoi(val.(string)) - return num - } - - return val - }), + "B": types.Any, }, // Node's Output Port Template @@ -115,7 +102,7 @@ func RegisterMathRandom() { // Node's Input Port Template TInput: engine.NodePortTemplate{ - "Re-seed": port.Trigger(func(port *engine.Port) { + "Re-seed": engine.Ports.Trigger(func(port *engine.Port) { node.Executed = true byt := make([]byte, 2) rand.Read(byt) diff --git a/port/types.go b/port/types.go deleted file mode 100644 index bf4c19c..0000000 --- a/port/types.go +++ /dev/null @@ -1,68 +0,0 @@ -package port - -import ( - "reflect" - - "github.com/blackprint/engine-go/engine" -) - -/* This port can contain multiple cable as input - * and the value will be array of 'type' - * it's only one type, not union - * for union port, please split it to different port to handle it - */ -func ArrayOf(type_ reflect.Kind) *engine.PortFeature { - return &engine.PortFeature{ - Id: engine.PortTypeArrayOf, - Type: type_, - } -} - -/* This port can have default value if no cable was connected - * type = Type Data that allowed for the Port - * value = default value for the port - */ -func Default(type_ reflect.Kind, val any) *engine.PortFeature { - return &engine.PortFeature{ - Id: engine.PortTypeDefault, - Type: type_, - Value: val, - } -} - -/* This port will be used as a trigger or callable input port - * func = callback when the port was being called as a function - */ -func Trigger(callback func(*engine.Port)) *engine.PortFeature { - return &engine.PortFeature{ - Id: engine.PortTypeTrigger, - Func: callback, - } -} - -/* This port can allow multiple different types - * like an 'any' port, but can only contain one value - */ -func Union(types []reflect.Kind) *engine.PortFeature { - return &engine.PortFeature{ - Id: engine.PortTypeUnion, - Types: types, - } -} - -/* This port can allow multiple different types - * like an 'any' port, but can only contain one value - */ -func StructOf(type_ reflect.Kind, structure map[string]engine.PortStructTemplate) *engine.PortFeature { - return &engine.PortFeature{ - Id: engine.PortTypeStructOf, - Type: type_, - Value: structure, - } -} - -func Route() *engine.PortFeature { - return &engine.PortFeature{ - Id: engine.PortTypeRoute, - } -} From 04783a20beb350227c31693ccf7f33db7bdeb1c4 Mon Sep 17 00:00:00 2001 From: StefansArya Date: Fri, 9 Sep 2022 08:45:20 +0700 Subject: [PATCH 08/15] Implement function node --- blackprint/nodesBPFunction.go | 316 ++++++++++++++++++++++++++++++++++ engine/engine.go | 70 ++++++-- engine/node.go | 10 +- engine/nodesBPFunction.go | 274 +++++++++++++++++++++++++++++ engine/port.go | 8 +- example/button.go | 2 +- 6 files changed, 659 insertions(+), 21 deletions(-) create mode 100644 engine/nodesBPFunction.go diff --git a/blackprint/nodesBPFunction.go b/blackprint/nodesBPFunction.go index 7f4119a..aae0d2b 100644 --- a/blackprint/nodesBPFunction.go +++ b/blackprint/nodesBPFunction.go @@ -1,5 +1,321 @@ package blackprint +import ( + "strconv" + "strings" + + "github.com/blackprint/engine-go/engine" + "github.com/blackprint/engine-go/engine/nodes" + "github.com/blackprint/engine-go/types" +) + +type nodeInput struct { + *engine.Node +} + +func (n *nodeInput) imported(data any) { + input := n.Iface.QFuncMain.Node.QFuncInstance.Input + + for key, value := range input { + n.CreatePort("output", key, value) + } +} + +func (n *nodeInput) request(cable *engine.Cable) { + name := cable.Output.Name + + // This will trigger the port to request from outside and assign to this node's port + n.Output[name].Set(n.Iface.QFuncMain.Node.Input[name].Get()) +} + +type nodeOutput struct { + *engine.Node +} + +func (n *nodeOutput) imported(data map[string]any) { + output := n.Iface.QFuncMain.Node.QFuncInstance.Output + + for key, value := range output { + n.CreatePort("input", key, value) + } +} + +func (n *nodeOutput) update(cable *engine.Cable) { + iface := n.Iface.QFuncMain + if cable == nil { // Triggered by port route + IOutput := iface.Output + Output := iface.Node.Output + thisInput := n.Input + + // Sync all port value + for key, value := range IOutput { + if value.Type == types.Function { + continue + } + Output[key].Set(thisInput[key].Get()) + } + + return + } + + iface.Node.Output[cable.Input.Name].Set(cable.GetValue()) +} + +type FnMain struct { + *engine.Interface + QImportOnce bool + QSave func(any, string, bool) + QPortSw_ any +} + +func (f *FnMain) QBpFnInit() { + if f.QImportOnce { + panic("Can't import function more than once") + } + + f.QImportOnce = true + node := f.Node + + f.QBpInstance = engine.New() + bpFunction := node.QFuncInstance + + newInstance := f.QBpInstance + // newInstance.Variables = []; // private for one function + newInstance.SharedVariables = bpFunction.Variables // shared between function + newInstance.Functions = node.Instance.Functions + newInstance.QFuncMain = f + newInstance.QMainInstance = bpFunction.RootInstance + + bpFunction.RefreshPrivateVars(newInstance) + + swallowCopy := make([]any, len(bpFunction.Structure)) + copy(swallowCopy, bpFunction.Structure) + + f.QBpInstance.ImportJSON(swallowCopy) + + // Init port switches + if f.QPortSw_ != nil { + f.QInitPortSwitches(f.QPortSw_) + f.QPortSw_ = nil + + InputIface := f.QProxyInput.Iface + if InputIface.QPortSw_ != nil { + InputIface.QInitPortSwitches(InputIface.QPortSw_) + InputIface.QPortSw_ = nil + } + } + + f.QSave = func(ev any, eventName string, force bool) { + if force || bpFunction.QSyncing { + return + } + + ev.BpFunction = bpFunction + newInstance.QMainInstance.Emit(eventName, ev) + + bpFunction.QSyncing = true + bpFunction.QOnFuncChanges(eventName, ev, f.Node) + bpFunction.QSyncing = false + } + + f.QBpInstance.On("cable.connect cable.disconnect node.created node.delete node.id.changed", f.QSave) +} +func (f *FnMain) RenamePort(which string, fromName string, toName string) { + f.Node.QFuncInstance.RenamePort(which, fromName, toName) + f.QSave(false, "", true) +} + +type bpFnInOut struct { + *engine.Interface +} + +type addPortRef struct { + Node *engine.Node + Port *engine.Port +} + +func (b *bpFnInOut) AddPort(port *engine.Port, customName string) *engine.Port { + if port == nil { + panic("Can't set type with nil") + } + + if strings.HasPrefix(port.Iface.Namespace, "BP/Fn") { + panic("Function Input can't be connected directly to Output") + } + + var name string + if port.Name_ != nil { + name = port.Name_.Name + } else if customName != "" { + name = customName + } else { + name = port.Name + } + + var reff *addPortRef + var portType any + if port.Feature == engine.PortTypeTrigger { + reff = &addPortRef{} + portType = engine.Ports.Trigger(func(*engine.Port) { + reff.Node.Output[reff.Port.Name].Call() + }) + } else { + if port.Feature != 0 { + portType = port.QGetPortFeature() + } else { + portType = port.Type + } + } + + var nodeA *engine.Node + var nodeB *engine.Node + // nodeA, nodeB; // Main (input) -> Input (output), Output (input) -> Main (output) + if b.Type == "bp-fn-input" { // Main (input) -> Input (output) + inc := 1 + for true { + _, exist := b.Output[name] + if !exist { + break + } + + name += strconv.Itoa(inc) + inc++ + } + + nodeA = b.QFuncMain.Node + nodeB = b.Node + nodeA.QFuncInstance.Input[name] = portType + } else { // Output (input) -> Main (output) + inc := 1 + for true { + _, exist := b.Input[name] + if !exist { + break + } + + name += strconv.Itoa(inc) + inc++ + } + + nodeA = b.Node + nodeB = b.QFuncMain.Node + nodeB.QFuncInstance.Output[name] = portType + } + + outputPort := nodeB.CreatePort("output", name, portType) + + var inputPort *engine.Port + if portType == types.Function { + inputPort = nodeA.CreatePort("input", name, engine.Ports.Trigger(outputPort.QCallAll)) + } else { + inputPort = nodeA.CreatePort("input", name, portType) + } + + if reff != nil { + reff.Node = nodeB + reff.Port = inputPort + } + + if b.Type == "bp-fn-input" { + outputPort.Name_ = &RefPortName{Name: name} // When renaming port, this also need to be changed + b.Emit("_add.{name}", outputPort) + + inputPort.On("value", func(ev engine.PortValueEvent) { + outputPort.Iface.Node.Output[outputPort.Name](ev.Cable.Output.Value) + }) + + return outputPort + } + + inputPort.Name_ = &RefPortName{Name: name} // When renaming port, this also need to be changed + b.Emit("_add.{name}", inputPort) + return inputPort +} + +func (b *bpFnInOut) renamePort(fromName string, toName string) { + bpFunction := b.QFuncMain.Node.QFuncInstance + // Main (input) -> Input (output) + if b.Type == "bp-fn-input" { + bpFunction.RenamePort("input", fromName, toName) + } else { // Output (input) -> Main (output) + bpFunction.RenamePort("output", fromName, toName) + } +} + +func (b *bpFnInOut) deletePort(name string) { + funcMainNode := b.QFuncMain.Node + if b.Type == "bp-fn-input" { // Main (input) -> Input (output) + funcMainNode.DeletePort("input", name) + b.Node.DeletePort("output", name) + delete(funcMainNode.QFuncInstance.Input, name) + } else { // Output (input) -> Main (output) + funcMainNode.DeletePort("output", name) + b.Node.DeletePort("input", name) + delete(funcMainNode.QFuncInstance.Output, name) + } +} + func registerBpFuncNode() { + RegisterNode("BP/Fn/Input", func(i *engine.Instance) any { + node := &nodeInput{ + Node: &engine.Node{ + Instance: i, + }, + } + + iface := node.SetInterface("BPIC/BP/Fn/Input").(*fnInput) + iface.QEnum = nodes.BPFnInput + iface.QProxyInput = true // Port is initialized dynamically + iface.QDynamicPort = true + + iface.Title = "Input" + iface.Type = "bp-fn-input" + iface.QFuncMain = i.QFuncMain + i.QFuncMain.QProxyInput = node + + return node + }) + + RegisterInterface("BPIC/BP/Fn/Input", func(node any) any { + return &bpFnInOut{ + Interface: &engine.Interface{ + Node: node, + }, + } + }) + + RegisterNode("BP/Fn/Output", func(i *engine.Instance) any { + node := &bpVarGet{ + Node: &engine.Node{ + Instance: i, + }, + } + + iface := node.SetInterface("BPIC/BP/Fn/Output").(*fnOutput) + iface.QEnum = nodes.BPFnOutput + iface.QDynamicPort = true // Port is initialized dynamically + + iface.Title = "Output" + iface.Type = "bp-fn-output" + iface.QFuncMain = i.QFuncMain + i.QFuncMain.QProxyOutput = node + + return node + }) + + RegisterInterface("BPIC/BP/Fn/Output", func(node any) any { + return &bpFnInOut{ + Interface: &engine.Interface{ + Node: node, + }, + } + }) + RegisterInterface("BPIC/BP/Fn/Main", func(node any) any { + return &FnMain{ + Interface: &engine.Interface{ + Node: node, + }, + } + }) } diff --git a/engine/engine.go b/engine/engine.go index f13ee8c..6862eb3 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -14,7 +14,7 @@ import ( var Event = &CustomEvent{} -type NodePortTemplate map[string]any +type NodePortTemplate map[string]any // any = reflect.Kind | portFeature type Instance struct { *CustomEvent Iface map[string]any // Storing with node id if exist @@ -27,7 +27,8 @@ type Instance struct { Functions map[string]*BPFunction Ref map[string]*ReferencesShortcut - QFuncMain // => *engine.Interface + QFuncMain *BPFunction // => *engine.Interface + QFuncInstance *Instance } func New() *Instance { @@ -115,7 +116,7 @@ func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inse } // Do we need this? - // instance.Emit("json.importing", {appendMode: options.appendMode, raw: json}); + // instance.Emit("json.importing", {appendMode: options.appendMode, raw: json}) ifaceList := instance.IfaceList var metadata metadataValue @@ -449,6 +450,8 @@ type varOptions struct { } func (instance *Instance) CreateVariable(id string, options any) *BPVariable { + id = createBPVariableRegx.ReplaceAllString(id, "_") + if old, exist := instance.Variables[id]; exist { old.Destroy() delete(instance.Variables, id) @@ -468,27 +471,68 @@ func (instance *Instance) CreateVariable(id string, options any) *BPVariable { } type funcOptions struct { - Id string `json:"id"` - Title string `json:"title"` - Vars []string `json:"vars"` - PrivateVars []string `json:"privateVars"` - Structure nodeList `json:"structure"` + Id string `json:"id"` + Title string `json:"title"` + Vars []string `json:"vars"` + PrivateVars []string `json:"privateVars"` + Structure SingleInstanceJSON `json:"structure"` } func (instance *Instance) CreateFunction(id string, options any) *BPFunction { + id = createBPVariableRegx.ReplaceAllString(id, "_") + if old, exist := instance.Functions[id]; exist { old.Destroy() delete(instance.Functions, id) } + options_ := options.(funcOptions) + + // This will be updated if the function sketch was modified + structure := options_.Structure + if structure == nil { + structure = SingleInstanceJSON{ + "BP/Fn/Input": nodeList{nodeConfig{I: 0}}, + "BP/Fn/Output": nodeList{nodeConfig{I: 1}}, + } + } + + title := id temp := &BPFunction{ - Id: id, - Title: id, - Type: 0, // Type not set + Id: id, + Title: title, + Type: 0, // Type not set + Structure: structure, + RootInstance: instance, + } + + uniqId := 0 + temp.Node = func(ins *Instance) *Node { + ins.QFuncInstance = instance + + node := &Node{ + Instance: ins, + QFuncInstance: temp, + TInput: temp.Input, + TOutput: temp.Output, + } + + node.Embed = &BPFunctionNode{Node: node} + + iface := node.SetInterface("BPIC/BP/Fn/Main") + iface.Type = "function" + iface.QEnum = nodes.BPFnMain + iface.Namespace = id + iface.Title = title + + uniqId += 1 + iface.uniqId = uniqId + + iface.QPrepare() + return node } - instance.Functions[id] = temp - options_ := options.(funcOptions) + instance.Functions[id] = temp for _, val := range options_.Vars { temp.CreateVariable(val, bpFnVarOptions{ diff --git a/engine/node.go b/engine/node.go index 1b4b267..c536dbf 100644 --- a/engine/node.go +++ b/engine/node.go @@ -9,20 +9,22 @@ import ( type Node struct { *CustomEvent Instance *Instance - Iface any // any = extends *engine.Interface + Iface *Interface DisablePorts bool Routes *RoutePort Ref *ReferencesShortcut // Port Template - TOutput map[string]any // any = port.Type or *port.Feature - TInput map[string]any // any = port.Type or *port.Feature - // TProperty map[string]any // any = port.Type or *port.Feature + TOutput *NodePortTemplate + TInput *NodePortTemplate + // TProperty *NodePortTemplate Output map[string]*PortOutputGetterSetter Input map[string]*PortInputGetterSetter // Property map[string]getterSetter + + QFuncInstance *BPFunction } type NodeHandler func(*Instance) any // any = extends *engine.Node diff --git a/engine/nodesBPFunction.go b/engine/nodesBPFunction.go new file mode 100644 index 0000000..c062fd6 --- /dev/null +++ b/engine/nodesBPFunction.go @@ -0,0 +1,274 @@ +package engine + +import ( + "fmt" + + "github.com/blackprint/engine-go/engine/nodes" + "github.com/blackprint/engine-go/types" + "github.com/blackprint/engine-go/utils" +) + +// Main function node +type BPFunctionNode struct { // Main function node -> BPI/F/{FunctionName} + Node *Node +} + +func (b *BPFunctionNode) Init() { + if b.Node.Iface.QImportOnce { + b.Iface.QBpFnInit() + } +} + +func (b *BPFunctionNode) Imported(data map[string]any) { + ins := b.Node.QFuncInstance + ins.Used = append(ins.Used, b.Node.Iface) +} + +func (b *BPFunctionNode) Update(cable *Cable) { + iface := b.Iface.QProxyInput.Iface + Output := iface.Node.Output + + if cable == nil { // Triggered by port route + thisInput := b.Input + + // Sync all port value + for key, value := range iface.Output { + if value.Type == types.Function { + continue + } + + Output[key].Set(thisInput[key]()) + } + + return + } + + // Update output value on the input node inside the function node + Output[cable.Input.Name].Set(cable.GetValue()) +} + +func (b *BPFunctionNode) Destroy() { + ins := b.Node.QFuncInstance + utils.RemoveItem(ins.Used, b.Node.Iface) +} + +// used for instance.createFunction +type BPFunction struct { // <= _funcInstance + *CustomEvent + Id string + Title string + Type int + Used *Interface + Input *NodePortTemplate + Output *NodePortTemplate + Structure SingleInstanceJSON + Variables map[string]BPVariable + PrivateVars []string + RootInstance *Instance + Node func(*Instance) *Node // Node constructor +} + +func (b *BPFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { + for _, iface_ := range b.Used { + if iface_.Node == fromNode { + continue + } + + nodeInstance := iface_.QBpInstance + nodeInstance.PendingRender = true // Force recalculation for cable position + + if eventName == "cable.connect" || eventName == "cable.disconnect" { + input := obj.Cable.Input + output := obj.Cable.Output + ifaceList := fromNode.Iface.QBpInstance.IfaceList + + // Skip event that also triggered when deleting a node + if input.Iface.QBpDestroy || output.Iface.QBpDestroy { + continue + } + + inputIface := nodeInstance.IfaceList[utils.IndexOf(ifaceList, input.Iface)] + if inputIface == nil { + panic("Failed to get node input iface index") + } + + outputIface := nodeInstance.IfaceList[utils.IndexOf(ifaceList, output.Iface)] + if outputIface == nil { + panic("Failed to get node output iface index") + } + + if inputIface.Namespace != input.Iface.Namespace { + fmt.Println(inputIface.Namespace + " !== " + input.Iface.Namespace) + panic("Input iface namespace was different") + } + + if outputIface.Namespace != output.Iface.Namespace { + fmt.Println(outputIface.Namespace + " !== " + output.Iface.Namespace) + panic("Output iface namespace was different") + } + + if eventName == "cable.connect" { + targetInput := inputIface.Input[input.Name] + targetOutput := outputIface.Output[output.Name] + + if targetInput == nil { + if inputIface.QEnum == nodes.BPFnOutput { + targetInput = inputIface.AddPort(targetOutput, output.Name) + } else { + panic("Output port was not found") + } + } + + if targetOutput == nil { + if outputIface.QEnum == nodes.BPFnInput { + targetOutput = outputIface.AddPort(targetInput, input.Name) + } else { + panic("Input port was not found") + } + } + + targetInput.ConnectPort(targetOutput) + } else if eventName == "cable.disconnect" { + cables := inputIface.Input[input.Name].Cables + outputPort := outputIface.Output[output.Name] + + for _, cable := range cables { + if cable.Output == outputPort { + cable.Disconnect() + break + } + } + } + } else if eventName == "node.created" { + iface := obj.Iface + nodeInstance.CreateNode(iface.Namespace, map[string]any{ + "data": iface.Data, + }) + } else if eventName == "node.delete" { + index := utils.IndexOf(fromNode.Iface.QBpInstance.IfaceList, obj.Iface) + if index == false { + panic("Failed to get node index") + } + + iface := nodeInstance.IfaceList[index] + if iface.Namespace != obj.Iface.Namespace { + fmt.Println(iface.Namespace + " " + obj.Iface.Namespace) + panic("Failed to delete node from other function instance") + } + + if eventName == "node.delete" { + nodeInstance.DeleteNode(iface) + } + } + } +} + +func (b *BPFunction) CreateNode(instance *Instance, options map[string]any) (any, []any) { + return instance.CreateNode(b.Node, options) +} + +func (b *BPFunction) CreateVariable(id string, options map[string]any) *BPVariable { + if _, exist := b.Variables[id]; exist { + panic("Variable id already exist: id") + } + + // deepProperty + + temp := &BPVariable{ + Id: id, + // options, + } + temp.FuncInstance = b + + if options["scope"] == VarScopeShared { + b.Variables[id] = temp + } else { + b.AddPrivateVars(id) + return temp + } + + b.Emit("variable.new", temp) + b.RootInstance.Emit("variable.new", temp) + return temp +} + +type EvVariableNew struct { + Id string + ScopeId int +} + +func (b *BPFunction) AddPrivateVars(id string) { + if utils.Contains(b.PrivateVars, id) { + return + } + + b.PrivateVars = append(b.PrivateVars, id) + + temp := &EvVariableNew{ + ScopeId: VarScopePrivate, + Id: id, + } + b.Emit("variable.new", temp) + b.RootInstance.Emit("variable.new", temp) + + for _, iface := range b.Used { + iface.QBpInstance.Variables[id] = &BPVariable{Id: id} + } +} + +func (b *BPFunction) RefreshPrivateVars(instance *Instance) { + vars := instance.Variables + for _, id := range b.PrivateVars { + vars[id] = &BPVariable{Id: id} + } +} + +func (b *BPFunction) RenamePort(which string, fromName string, toName string) { + var main NodePortTemplate + var proxyPort string + if which == "output" { + main = *b.Output + proxyPort = "input" + } else { + main = *b.Input + proxyPort = "output" + } + + main[toName] = main[fromName] + delete(main, fromName) + + for _, iface := range b.Used { + iface.Node.RenamePort(which, fromName, toName) + + var temp *Node + if which == "output" { + temp = iface.QProxyOutput + } else { + temp = iface.QProxyInput + } + + temp.Iface[proxyPort][fromName].Name_.Name = toName + temp.RenamePort(proxyPort, fromName, toName) + + for _, proxyVar := range iface.BpInstance.IfaceList { + if (which == "output" && proxyVar.Namespace != "BP/FnVar/Output") || (which == "input" && proxyVar.Namespace != "BP/FnVar/Input") { + continue + } + + if proxyVar.Data.Name != fromName { + continue + } + proxyVar.Data.Name = toName + + if which == "output" { + proxyVar[proxyPort]["Val"].Name_.Name = toName + } + } + } +} + +func (b *BPFunction) Destroy() { + for _, iface := range b.Used { + iface.Node.Instance.DeleteNode(iface) + } +} diff --git a/engine/port.go b/engine/port.go index f5bbc9e..54a1493 100644 --- a/engine/port.go +++ b/engine/port.go @@ -17,7 +17,7 @@ type PortStructTemplate struct { type Port struct { CustomEvent Name string - Name_ *RefPortName // ToDo: fill alternate name, search in engine-php _name for hints + Name_ *RefPortName // For BPFunction only, ToDo: fill alternate name, search in engine-php _name for hints Type reflect.Kind Types []reflect.Kind Cables []*Cable @@ -45,6 +45,8 @@ type Port struct { OnConnect func(*Cable, *Port) } +/** For internal library use only */ +// For BPFunction only type RefPortName struct { Name string } @@ -242,7 +244,7 @@ func (port *Port) ConnectCable(cable *Cable) bool { // Golang can't check by class instance or inheritance // ========================================== // ToDo: recheck why we need to check if the constructor is a function - // isInstance = true; + // isInstance = true // if cable.Owner.Type != port.Type && cable.Owner.Type == types.Function && port.Type == types.Function { // if cable.Owner.Source == PortOutput{ // isInstance = cable.Owner.Type instanceof port.Type @@ -335,7 +337,7 @@ func (port *Port) ConnectCable(cable *Cable) bool { // Connect this cable into port's cable list port.Cables = append(port.Cables, cable) - // cable.Connecting(); + // cable.Connecting() cable.QConnected() return true diff --git a/example/button.go b/example/button.go index d0ff54d..e34b9e0 100644 --- a/example/button.go +++ b/example/button.go @@ -24,7 +24,7 @@ func (iface *ButtonSimpleIFace) Clicked(ev any) { // This will be called from example.go func RegisterButton() { - ButtonSimpleOutput := engine.NodePortTemplate{ + ButtonSimpleOutput := &engine.NodePortTemplate{ "Clicked": types.Function, } From 8db514b292ecb5fa9c3c71715b3cec04290af958 Mon Sep 17 00:00:00 2001 From: StefansArya Date: Fri, 9 Sep 2022 14:08:18 +0700 Subject: [PATCH 09/15] Fix example for the design changes --- .gitignore | 3 +- blackprint/blackprint.go | 11 +-- blackprint/nodesBPFunction.go | 2 +- blackprint/nodesBPVariable.go | 39 +++------ blackprint/nodesEnvironment.go | 2 +- blackprint/nodesFnPortVar.go | 2 +- engine/bpVar.go | 8 +- engine/cable.go | 8 +- engine/engine.go | 74 ++++++++-------- engine/interface.go | 49 ++++++++--- engine/node.go | 94 +++++++++++++-------- engine/port.go | 2 +- engine/portFeature.go | 11 +-- engine/portGetterSetter.go | 13 +-- engine/references.go | 2 +- engine/routePort.go | 32 +++---- example/button.go | 56 ++++++------ example/example.go | 8 -- example/example_test.go | 10 +-- example/input.go | 64 +++++++------- example/logger.go | 63 ++++++-------- example/math.go | 150 +++++++++++++++------------------ 22 files changed, 331 insertions(+), 372 deletions(-) delete mode 100644 example/example.go diff --git a/.gitignore b/.gitignore index 9b79cfb..4a94c7a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .vscode/ -*.exe \ No newline at end of file +*.exe +utils/test.go \ No newline at end of file diff --git a/blackprint/blackprint.go b/blackprint/blackprint.go index da5981d..7ab8b14 100644 --- a/blackprint/blackprint.go +++ b/blackprint/blackprint.go @@ -7,12 +7,12 @@ import ( ) // The constructor must return pointer (ex: &Node{}) -func RegisterNode(namespace string, constructor func(*engine.Instance) any) { +func RegisterNode(namespace string, meta *engine.NodeMetadata, constructor engine.NodeConstructor) { engine.QNodeList[namespace] = constructor } // The constructor must return pointer (ex: &any) -func RegisterInterface(namespace string, constructor func(any) any) { +func RegisterInterface(namespace string, constructor engine.InterfaceConstructor) { if strings.HasPrefix(namespace, "BPIC/") == false { panic(namespace + ": The first parameter of 'RegisterInterface' must be started with BPIC to avoid name conflict. Please name the interface similar with 'templatePrefix' for your module that you have set on 'blackprint.config.js'.") } @@ -22,10 +22,3 @@ func RegisterInterface(namespace string, constructor func(any) any) { var Event = engine.Event var Environment = engine.QEnvironment - -func init() { - registerEnvNode() - registerBpPortVarNode() - registerBpFuncNode() - registerBpPortVarNode() -} diff --git a/blackprint/nodesBPFunction.go b/blackprint/nodesBPFunction.go index aae0d2b..0044a57 100644 --- a/blackprint/nodesBPFunction.go +++ b/blackprint/nodesBPFunction.go @@ -255,7 +255,7 @@ func (b *bpFnInOut) deletePort(name string) { } } -func registerBpFuncNode() { +func init() { RegisterNode("BP/Fn/Input", func(i *engine.Instance) any { node := &nodeInput{ Node: &engine.Node{ diff --git a/blackprint/nodesBPVariable.go b/blackprint/nodesBPVariable.go index 1e8bb71..110e4ce 100644 --- a/blackprint/nodesBPVariable.go +++ b/blackprint/nodesBPVariable.go @@ -1,7 +1,6 @@ package blackprint import ( - "reflect" "strconv" "github.com/blackprint/engine-go/engine" @@ -47,7 +46,7 @@ func (b *bpVarGetSet) ChangeVar(name string, scopeId int) map[string]*engine.BPV b.Data["name"] = &engine.GetterSetter{Value: name} b.Data["scope"] = &engine.GetterSetter{Value: scopeId} - thisInstance := utils.GetProperty(b.Node, "Instance").(*engine.Instance) + thisInstance := b.Node.Instance.(*engine.Instance) funcInstance := thisInstance.QFuncMain if funcInstance == nil { funcInstance.Node.QFuncInstance @@ -105,7 +104,7 @@ func (b *bpVarGetSet) UseType_(port *engine.Port, targetPort *engine.Port) { // Also create port for other node that using $this variable for _, item := range b.QBpVarRef.Used { - utils.CallFunction(item, "QReinitPort", utils.EmptyArgs) + item.QReinitPort() } } @@ -162,16 +161,11 @@ func (b *iVarSet) QReinitPort() *engine.Port { node := b.Node if b.Output["Val"] != nil { - utils.CallFunction(node, "DeletePort", &[]reflect.Value{ - reflect.ValueOf("Val"), - }) + node.DeletePort("Val") } - ref := utils.GetProperty(b.Node, "Output").(map[string]*engine.PortOutputGetterSetter) - utils.CallFunction(b.Node, "CreatePort", &[]reflect.Value{ - reflect.ValueOf("Val"), - reflect.ValueOf(temp.Type), - }) + ref := b.Node.Output.(map[string]*engine.PortOutputGetterSetter) + b.Node.CreatePort("Val", temp.Type) if temp.Type == types.Function { b.QEventListen = "call" @@ -226,32 +220,21 @@ func (b *iVarGet) QReinitPort() *engine.Port { temp := b.QBpVarRef if _, exist := input["Val"]; exist { - utils.CallFunction(node, "DeletePort", &[]reflect.Value{ - reflect.ValueOf("Input"), - reflect.ValueOf("Val"), - }) + node.DeletePort("Input", "Val") } if temp.Type == types.Function { - utils.CallFunction(node, "CreatePort", &[]reflect.Value{ - reflect.ValueOf("Input"), - reflect.ValueOf("Val"), - reflect.ValueOf(engine.Ports.Trigger(func(p *engine.Port) { - temp.Emit("call", nil) - })), - }) + node.CreatePort("Input", "Val", engine.Ports.Trigger(func(p *engine.Port) { + temp.Emit("call", nil) + })) } else { - utils.CallFunction(node, "CreatePort", &[]reflect.Value{ - reflect.ValueOf("Input"), - reflect.ValueOf("Val"), - reflect.ValueOf(temp.Type), - }) + node.CreatePort("Input", "Val", temp.Type) } return b.Input["Val"] } -func registerBPVarNode() { +func init() { RegisterNode("BP/Var/Set", func(i *engine.Instance) any { node := &bpVarSet{ Node: &engine.Node{ diff --git a/blackprint/nodesEnvironment.go b/blackprint/nodesEnvironment.go index 96947d0..ef1130f 100644 --- a/blackprint/nodesEnvironment.go +++ b/blackprint/nodesEnvironment.go @@ -67,7 +67,7 @@ type iEnvSet struct { *bpEnvGetSet } -func registerEnvNode() { +func init() { RegisterNode("BP/Env/Get", func(i *engine.Instance) any { node := &bpEnvGet{ Node: &engine.Node{ diff --git a/blackprint/nodesFnPortVar.go b/blackprint/nodesFnPortVar.go index 40fa9d3..76a2ec1 100644 --- a/blackprint/nodesFnPortVar.go +++ b/blackprint/nodesFnPortVar.go @@ -251,7 +251,7 @@ func getFnPortType(port *engine.Port, which string, parentNode any, ref *engine. } } -func registerFnVarNode() { +func init() { RegisterNode("BP/FnVar/Input", func(i *engine.Instance) any { node := &fnVarInput{ Node: &engine.Node{ diff --git a/engine/bpVar.go b/engine/bpVar.go index 3090e05..07c59e4 100644 --- a/engine/bpVar.go +++ b/engine/bpVar.go @@ -2,8 +2,6 @@ package engine import ( "reflect" - - "github.com/blackprint/engine-go/utils" ) type bpVarValue struct { @@ -33,10 +31,8 @@ type BPVariable struct { func (b *BPVariable) Destroy() { for _, iface := range b.Used { - ins := utils.GetProperty((utils.GetProperty(iface, "Node")), "Instance").(*Instance) - utils.CallFunction(ins, "DeleteNode", &[]reflect.Value{ - reflect.ValueOf(iface), - }) + ins := (iface.Node).Instance.(*Instance) + ins.DeleteNode(iface) } b.Used = b.Used[:0] diff --git a/engine/cable.go b/engine/cable.go index 55a241f..c054596 100644 --- a/engine/cable.go +++ b/engine/cable.go @@ -78,9 +78,7 @@ func (c *Cable) QConnected() { c.Input.Emit("value", inputEv) c.Input.Iface.Emit("value", inputEv) - utils.CallFunction(c.Input.Iface.Node, "Update", &[]reflect.Value{ - reflect.ValueOf(c), - }) + c.Input.Iface.Node.Update(c) } // For debugging @@ -129,7 +127,7 @@ func (c *Cable) Disconnect(which_ ...*Port) { // which = port c.Owner.Emit("disconnect", temp) c.Owner.Iface.Emit("cable.disconnect", temp) - ins := utils.GetPropertyRef(c.Owner.Iface.Node, "Instance").(*Instance) + ins := c.Owner.Iface.Node.Instance.(*Instance) ins.Emit("cable.disconnect", temp) alreadyEmitToInstance = true @@ -155,7 +153,7 @@ func (c *Cable) Disconnect(which_ ...*Port) { // which = port c.Target.Iface.Emit("cable.disconnect", temp) if alreadyEmitToInstance == false { - ins := utils.GetPropertyRef(c.Target.Iface.Node, "Instance").(*Instance) + ins := c.Target.Iface.Node.Instance.(*Instance) ins.Emit("cable.disconnect", temp) } } diff --git a/engine/engine.go b/engine/engine.go index 6862eb3..ea68c0c 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -3,7 +3,6 @@ package engine import ( "encoding/json" "fmt" - "reflect" "regexp" "strings" @@ -17,15 +16,15 @@ var Event = &CustomEvent{} type NodePortTemplate map[string]any // any = reflect.Kind | portFeature type Instance struct { *CustomEvent - Iface map[string]any // Storing with node id if exist - IfaceList []any // Storing with node index + Iface map[string]*Interface // Storing with node id if exist + IfaceList []*Interface // Storing with node index settings map[string]bool DisablePorts bool PanicOnError bool Variables map[string]*BPVariable Functions map[string]*BPFunction - Ref map[string]*ReferencesShortcut + Ref map[string]*referencesShortcut QFuncMain *BPFunction // => *engine.Interface QFuncInstance *Instance @@ -33,8 +32,8 @@ type Instance struct { func New() *Instance { return &Instance{ - Iface: map[string]any{}, - IfaceList: map[int]any{}, + Iface: map[string]*Interface{}, + IfaceList: []*Interface{}, settings: map[string]bool{}, PanicOnError: true, } @@ -158,7 +157,7 @@ func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inse temp, inserted = instance.CreateNode(namespace, iface, inserted) ifaceList[iface.I] = temp - utils.CallFunction(temp, "QBpFnInit", utils.EmptyArgs) + temp.QBpFnInit() } } @@ -177,7 +176,7 @@ func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inse // If have output connection out := ifaceJSON.Output if out != nil { - Output := *utils.GetPropertyRef(iface, "Output").(*map[string]*Port) + Output := *iface.Output.(*map[string]*Port) // Every output port that have connection for portName, ports := range out { @@ -206,11 +205,11 @@ func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inse targetNode := ifaceList[target.I] // output can only meet input port - Input := *utils.GetPropertyRef(targetNode, "Input").(*map[string]*Port) + Input := *targetNode.Input.(*map[string]*Port) linkPortB := Input[target.Name] if linkPortB == nil { - targetTitle := utils.GetProperty(targetNode, "Title").(string) + targetTitle := targetNode.Title.(string) if targetNode.QEnum == nodes.BPFnOutput { linkPortB = targetNode.AddPort(linkPortA, target) @@ -229,8 +228,8 @@ func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inse } // For Debugging -> - // Title := utils.GetProperty(iface, "Title").(string) - // targetTitle := utils.GetProperty(targetNode, "Title").(string) + // Title := iface.Title.(string) + // targetTitle := targetNode.Title.(string) // fmt.Printf("%s.%s => %s.%s\n", Title, linkPortA.Name, targetTitle, linkPortB.Name) // <- For Debugging @@ -244,7 +243,7 @@ func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inse // Call nodes init after creation processes was finished for _, val := range inserted { - utils.CallFunction(val, "Init", utils.EmptyArgs) + val.Init() } return @@ -327,22 +326,22 @@ func (instance *Instance) Settings(id string, val ...bool) bool { return temp } -func (instance *Instance) GetNode(id any) any { +// Deprecated, use instance.Iface or instance.IfaceList instead +func (instance *Instance) GetNode(id any) *Interface { for _, val := range instance.IfaceList { - temp := reflect.ValueOf(val).Elem() - if temp.FieldByName("Id").Interface().(string) == id || temp.FieldByName("I").Interface().(int) == id { - return utils.GetProperty(val, "Node") + if val.Id == id.(string) || val.I == id.(int) { + return val } } return nil } -func (instance *Instance) GetNodes(namespace string) []any { - var got []any // any = extends 'engine.Node' +func (instance *Instance) GetNodes(namespace string) []*Interface { + var got []*Interface for _, val := range instance.IfaceList { - if utils.GetProperty(val, "Namespace").(string) == namespace { - got = append(got, utils.GetProperty(val, "Node")) + if val.Namespace == namespace { + got = append(got, val) } } @@ -352,8 +351,9 @@ func (instance *Instance) GetNodes(namespace string) []any { // ToDo: sync with JS, when creating function node this still broken func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes []any) (any, []any) { func_ := QNodeList[namespace] - var node any // *node: extends engine.Node + var node *Node var isFuncNode bool + if func_ == nil { if strings.HasPrefix(namespace, "BPI/F/") { temp := instance.Functions[namespace] @@ -381,21 +381,21 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes } // *iface: extends engine.Interface - iface := utils.GetProperty(node, "Iface") - if iface == nil || utils.GetProperty(iface, "QInitialized").(bool) == false { + iface := node.Iface + if iface == nil || iface.QInitialized.(bool) == false { panic(namespace + ": Node interface was not found, do you forget to call node.SetInterface() ?") } - utils.SetProperty(iface, "Node", node) - utils.SetProperty(iface, "Namespace", namespace) + iface.Node = node + iface.Namespace = namespace // Create the linker between the nodes and the iface if isFuncNode == false { - utils.CallFunction(iface, "QPrepare", utils.EmptyArgs) + iface.QPrepare() } if options.Id != "" { - utils.SetProperty(iface, "Id", options.Id) + iface.Id = options.Id instance.Iface[options.Id] = iface instance.Ref[options.Id] = iface.Ref @@ -405,14 +405,14 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes } } - utils.SetProperty(iface, "I", options.I) + iface.I = options.I instance.IfaceList[options.I] = iface if options.InputDefault != nil { iface.QImportInputs(options.InputDefault) } - savedData := &[]reflect.Value{reflect.ValueOf(options.Data)} + savedData := options.Data.(map[string]any) if options.OutputSwitch != nil { for key, val := range options.OutputSwitch { @@ -426,17 +426,17 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes } } - utils.SetProperty(iface, "Importing", false) + iface.Importing = false - utils.CallFunction(iface, "Imported", savedData) - utils.CallFunction(node, "Imported", savedData) + iface.Imported(savedData) + node.Imported(savedData) - utils.CallFunction(iface, "Init", utils.EmptyArgs) + iface.Init() if nodes != nil { nodes = append(nodes, node) } else { // Init now if not A batch creation - utils.CallFunction(node, "Init", utils.EmptyArgs) + node.Init() } return iface, nodes @@ -550,7 +550,7 @@ func (instance *Instance) CreateFunction(id string, options any) *BPFunction { type NodeLogEvent struct { Instance *Instance - Iface any + Iface *Interface IfaceTitle string Message string } @@ -559,7 +559,7 @@ func (instance *Instance) QLog(iface any, message string) { evData := NodeLogEvent{ Instance: instance, Iface: iface, - IfaceTitle: utils.GetProperty(iface, "Title").(string), + IfaceTitle: iface.Title.(string), Message: message, } diff --git a/engine/interface.go b/engine/interface.go index 39d1f8a..aeab353 100644 --- a/engine/interface.go +++ b/engine/interface.go @@ -9,6 +9,27 @@ import ( var portList = [3]string{"Input", "Output", "Property"} +type embedInterface interface { + Init() + Request(*Cable) + Update(*Cable) + Imported(map[string]any) + Destroy() + SyncIn(id string, data ...any) +} + +type EmbedInterface struct { + embedInterface + Node *Node + Iface *Interface + Ref *referencesShortcut +} + +// To be overriden by module developer +func (iface *EmbedInterface) Init() {} +func (iface *EmbedInterface) Destroy() {} +func (iface *EmbedInterface) Imported(data map[string]any) {} + type InterfaceData map[string]getterSetter type Interface struct { *CustomEvent @@ -22,9 +43,10 @@ type Interface struct { Output map[string]*Port Input map[string]*Port Data InterfaceData - Node any // any = extends *engine.Node + Node *Node + Embed embedInterface - Ref *ReferencesShortcut + Ref *referencesShortcut IsGhost bool Importing bool @@ -39,9 +61,9 @@ type Interface struct { } // To be overriden -func (iface *Interface) Init() {} -func (iface *Interface) Destroy() {} -func (iface *Interface) Imported(data any) {} +func (i *Interface) Init() { i.Embed.Init() } +func (i *Interface) Destroy() { i.Embed.Destroy() } +func (i *Interface) Imported(data map[string]any) { i.Embed.Imported(data) } // Internal blackprint function node initialization func (iface *Interface) QBpFnInit() {} @@ -49,26 +71,25 @@ func (iface *Interface) QBpFnInit() {} var reflectKind = reflect.TypeOf(reflect.Int) // Private (to be called for internal library only) -func (iface *Interface) QPrepare() { +func (iface *Interface) QPrepare(meta *NodeMetadata) { iface.CustomEvent = &CustomEvent{} - ref := &ReferencesShortcut{} + ref := &referencesShortcut{} node := iface.Node - utils.SetProperty(node, "Ref", ref) + node.Ref = ref iface.Ref = ref - utils.SetProperty(node, "Route", &RoutePort{Iface: iface}) + node.Route = &RoutePort{Iface: iface} for i := 0; i < 3; i++ { which := portList[i] - port := *utils.GetPropertyRef(node, "T"+which).(*map[string]any) // get value by property name + port := utils.GetProperty(meta, which).(NodePortTemplate) // get value by property name if port == nil { continue } ifacePort := map[string]*Port{} - utils.SetProperty(iface, which, ifacePort) var inputUpgradePort map[string]*PortInputGetterSetter var outputUpgradePort map[string]*PortOutputGetterSetter @@ -78,13 +99,15 @@ func (iface *Interface) QPrepare() { ref.Input = inputUpgradePort ref.IInput = ifacePort - utils.SetProperty(node, which, inputUpgradePort) + iface.Input = ifacePort + node.Input = inputUpgradePort } else { outputUpgradePort = map[string]*PortOutputGetterSetter{} ref.Output = outputUpgradePort ref.IOutput = ifacePort - utils.SetProperty(node, which, outputUpgradePort) + iface.Output = ifacePort + node.Output = outputUpgradePort } // name: string diff --git a/engine/node.go b/engine/node.go index c536dbf..7d30db1 100644 --- a/engine/node.go +++ b/engine/node.go @@ -1,24 +1,41 @@ package engine import ( - "reflect" - "github.com/blackprint/engine-go/utils" ) +type embedNode interface { + Init() + Request(*Cable) + Update(*Cable) + Imported(map[string]any) + Destroy() + SyncIn(id string, data ...any) +} + +type EmbedNode struct { + embedNode + Node *Node + Iface *Interface + Ref *referencesShortcut +} + +// To be overriden by module developer +func (n *EmbedNode) Init() {} +func (n *EmbedNode) Request(*Cable) {} +func (n *EmbedNode) Update(*Cable) {} +func (n *EmbedNode) Imported(map[string]any) {} +func (n *EmbedNode) Destroy() {} +func (n *EmbedNode) SyncIn(id string, data ...any) {} + type Node struct { - *CustomEvent Instance *Instance Iface *Interface DisablePorts bool Routes *RoutePort + Embed embedNode - Ref *ReferencesShortcut - - // Port Template - TOutput *NodePortTemplate - TInput *NodePortTemplate - // TProperty *NodePortTemplate + Ref *referencesShortcut Output map[string]*PortOutputGetterSetter Input map[string]*PortInputGetterSetter @@ -27,17 +44,32 @@ type Node struct { QFuncInstance *BPFunction } -type NodeHandler func(*Instance) any // any = extends *engine.Node -type InterfaceHandler func(any) any // any = extends *engine.Node, *engine.Interface +// Proxies, for library only +func (n *Node) Init() { n.Embed.Init() } +func (n *Node) Request(c *Cable) { n.Embed.Request(c) } +func (n *Node) Update(c *Cable) { n.Embed.Update(c) } +func (n *Node) Imported(d map[string]any) { n.Embed.Imported(d) } +func (n *Node) Destroy() { n.Embed.Destroy() } +func (n *Node) SyncIn(id string, data ...any) { n.Embed.SyncIn(id, data) } + +type NodeMetadata struct { + // Port Template + Output NodePortTemplate + Input NodePortTemplate + // Property *NodePortTemplate +} + +type NodeConstructor func(*Instance) *Node +type InterfaceConstructor func(*Node) *Interface // QNodeList = Private function, for internal library only -var QNodeList = map[string]NodeHandler{} +var QNodeList = map[string]NodeConstructor{} // QInterfaceList = Private function, for internal library only -var QInterfaceList = map[string]InterfaceHandler{} +var QInterfaceList = map[string]InterfaceConstructor{} // This will return *pointer -func (n *Node) SetInterface(namespace ...string) any { +func (n *Node) SetInterface(namespace ...string) *Interface { if len(namespace) == 0 { // Default interface (BP/Default) iface := &Interface{QInitialized: true, Importing: true} @@ -58,17 +90,17 @@ func (n *Node) SetInterface(namespace ...string) any { panic(".registerInterface() must return pointer") } - data := utils.GetProperty(iface, "Data") + data := iface.Data if data != nil { _data := data.(InterfaceData) for _, port := range _data { - utils.SetProperty(port, "Iface", iface) + port.Iface = iface } } - utils.SetProperty(iface, "QInitialized", true) - utils.SetProperty(iface, "Importing", true) + iface.QInitialized = true + iface.Importing = true n.Iface = iface n.CustomEvent = &CustomEvent{} @@ -76,18 +108,14 @@ func (n *Node) SetInterface(namespace ...string) any { } func (n *Node) CreatePort(which string, name string, config_ any) *Port { - port := utils.CallFunction(n.Iface, "QCreatePort", &[]reflect.Value{ - reflect.ValueOf(which), - reflect.ValueOf(name), - reflect.ValueOf(config_), - }).(*Port) + port := n.Iface.QCreatePort(which, name, config_) if which != "input" { - ifacePort := utils.GetProperty(n.Iface, "Input").(map[string]*Port) + ifacePort := n.Iface.Input.(map[string]*Port) ifacePort[name] = port n.Input[name] = &PortInputGetterSetter{port: port} } else if which != "output" { - ifacePort := utils.GetProperty(n.Iface, "Output").(map[string]*Port) + ifacePort := n.Iface.Output.(map[string]*Port) ifacePort[name] = port n.Output[name] = &PortOutputGetterSetter{port: port} } else { @@ -100,9 +128,9 @@ func (n *Node) CreatePort(which string, name string, config_ any) *Port { func (n *Node) RenamePort(which string, name string, to string) { var portList map[string]*Port if which == "input" { - portList = utils.GetProperty(n.Iface, "Input").(map[string]*Port) + portList = n.Iface.Input.(map[string]*Port) } else if which == "output" { - portList = utils.GetProperty(n.Iface, "Output").(map[string]*Port) + portList = n.Iface.Output.(map[string]*Port) } else { panic("Can only rename port for 'input' and 'output'") } @@ -135,7 +163,7 @@ func (n *Node) DeletePort(which string, name string) { var port *Port if which != "input" { - ports = utils.GetProperty(n.Iface, "Input").(map[string]*Port) + ports = n.Iface.Input.(map[string]*Port) port = ports[name] if port == nil { return @@ -143,7 +171,7 @@ func (n *Node) DeletePort(which string, name string) { delete(n.Input, name) } else if which != "output" { - ports = utils.GetProperty(n.Iface, "Output").(map[string]*Port) + ports = n.Iface.Output.(map[string]*Port) port = ports[name] if port == nil { return @@ -161,11 +189,3 @@ func (n *Node) DeletePort(which string, name string) { func (n *Node) Log(message string) { n.Instance.QLog(n.Iface, message) } - -// To be overriden by module developer -func (n *Node) Init() {} -func (n *Node) Request(*Cable) {} -func (n *Node) Update(*Cable) {} -func (n *Node) Imported(map[string]any) {} -func (n *Node) Destroy() {} -func (n *Node) SyncOut(id string, data ...any) {} diff --git a/engine/port.go b/engine/port.go index 54a1493..5ba264d 100644 --- a/engine/port.go +++ b/engine/port.go @@ -22,7 +22,7 @@ type Port struct { Types []reflect.Kind Cables []*Cable Source int - Iface any + Iface *Interface Default any // Dynamic data (depend on Type) for storing port value (int, string, map, etc..) Value any // Dynamic data (depend on Type) for storing port value (int, string, map, etc..) Sync bool diff --git a/engine/portFeature.go b/engine/portFeature.go index 60bdcee..a3301ea 100644 --- a/engine/portFeature.go +++ b/engine/portFeature.go @@ -1,8 +1,6 @@ package engine import ( - "reflect" - "github.com/blackprint/engine-go/types" "github.com/blackprint/engine-go/utils" ) @@ -55,7 +53,7 @@ func portStructOf_split(port *Port) { port.Splitted = true port.DisconnectAll() - portData := utils.GetProperty(node, "Output").(map[string]*PortOutputGetterSetter)[port.Name] + portData := node.Output.(map[string]*PortOutputGetterSetter)[port.Name] if portData != nil { portStructOf_handle(port, portData) } @@ -71,15 +69,12 @@ func portStructOf_unsplit(port *Port) { node := port.Iface.Node for key, _ := range parent.Struct { - utils.CallFunction(node, "DeletePort", &[]reflect.Value{ - reflect.ValueOf("output"), - reflect.ValueOf(parent.Name + key), - }) + node.DeletePort("output", parent.Name+key) } } func portStructOf_handle(port *Port, data any) { - output := utils.GetProperty(port.Iface.Node, "Output").(map[string]*PortOutputGetterSetter) + output := port.Iface.Node.Output.(map[string]*PortOutputGetterSetter) if data != nil { for key, val := range port.Struct { diff --git a/engine/portGetterSetter.go b/engine/portGetterSetter.go index 60fcf71..dc60cc6 100644 --- a/engine/portGetterSetter.go +++ b/engine/portGetterSetter.go @@ -1,10 +1,7 @@ package engine import ( - "reflect" - "github.com/blackprint/engine-go/types" - "github.com/blackprint/engine-go/utils" ) type PortInputGetterSetter struct { @@ -53,10 +50,7 @@ func (gs *PortInputGetterSetter) Get() any { if target.Value == nil { port.Iface.QRequesting = true - utils.CallFunction(target.Iface.Node, "Request", &[]reflect.Value{ - reflect.ValueOf(target), - reflect.ValueOf(port.Iface), - }) + target.Iface.Node.Request(target, port.Iface) port.Iface.QRequesting = false } @@ -92,10 +86,7 @@ func (gs *PortInputGetterSetter) Get() any { if target.Value == nil { port.Iface.QRequesting = true - utils.CallFunction(target.Iface.Node, "Request", &[]reflect.Value{ - reflect.ValueOf(target), - reflect.ValueOf(port.Iface), - }) + target.Iface.Node.Request(target, port.Iface) port.Iface.QRequesting = false } diff --git a/engine/references.go b/engine/references.go index ade6a9c..7b66f16 100644 --- a/engine/references.go +++ b/engine/references.go @@ -1,6 +1,6 @@ package engine -type ReferencesShortcut struct { +type referencesShortcut struct { IInput map[string]*Port Input map[string]*PortInputGetterSetter IOutput map[string]*Port diff --git a/engine/routePort.go b/engine/routePort.go index d2c6a3f..a0a4ffb 100644 --- a/engine/routePort.go +++ b/engine/routePort.go @@ -1,8 +1,6 @@ package engine import ( - "reflect" - "github.com/blackprint/engine-go/engine/nodes" "github.com/blackprint/engine-go/utils" ) @@ -14,7 +12,7 @@ type RoutePort struct { DisableOut bool Disabled bool IsRoute bool - Iface any // any = extends *engine.Interface + Iface *engine.Interface // for internal library use only QIsPaused bool @@ -44,7 +42,7 @@ func (r *RoutePort) RouteTo(iface any) { return } - port := utils.GetProperty(utils.GetProperty(iface, "Node"), "Routes").(*RoutePort) + port := iface.Node.Routes.(*RoutePort) cable := NewCable(r.Port, port.Port) cable.IsRoute = true @@ -69,13 +67,11 @@ func (r *RoutePort) ConnectCable(cable *Cable) bool { } func (r *RoutePort) RouteIn(cable *Cable) { - node := utils.GetProperty(r.Iface, "Node") - utils.CallFunction(node, "Update", &[]reflect.Value{ - reflect.ValueOf(cable), - }) + node := r.Iface.Node + node.Update(cable) - routes := utils.GetProperty(node, "Routes") - utils.CallFunction(routes, "RouteOut", utils.EmptyArgs) + routes := node.Routes + routes.RouteOut() } func (r *RoutePort) RouteOut() { @@ -84,10 +80,10 @@ func (r *RoutePort) RouteOut() { } if r.Out == nil { - if utils.GetProperty(r.Iface, "QEnum").(int) == nodes.BPFnOutput { - node := utils.GetProperty(utils.GetProperty(r.Iface, "QFuncMain"), "Node") - route := utils.GetProperty(node, "Routes").(*RoutePort) - utils.CallFunction(route, "RouteIn", utils.EmptyArgs) + if r.Iface.QEnum.(int) == nodes.BPFnOutput { + node := r.Iface.QFuncMain.Node + route := node.Routes.(*RoutePort) + route.RouteIn() } return @@ -98,16 +94,16 @@ func (r *RoutePort) RouteOut() { return } - enum := utils.GetProperty(targetRoute.Iface, "QEnum").(int) + enum := targetRoute.Iface.QEnum.(int) if enum == 0 { targetRoute.RouteIn(r.Out) } else if enum == nodes.BPFnMain { - routes := utils.GetProperty(utils.GetProperty(targetRoute.Iface, "QProxyInput"), "Routes").(*RoutePort) + routes := targetRoute.Iface.QProxyInput.Routes.(*RoutePort) routes.RouteIn(r.Out) } else if enum == nodes.BPFnOutput { - node := utils.GetProperty(utils.GetProperty(targetRoute.Iface, "QFuncMain"), "Node") - routes := utils.GetProperty(node, "Routes").(*RoutePort) + node := targetRoute.Iface.QFuncMain.Node + routes := node.Routes.(*RoutePort) routes.RouteIn(r.Out) } else { targetRoute.RouteIn(r.Out) diff --git a/example/button.go b/example/button.go index e34b9e0..bb2f271 100644 --- a/example/button.go +++ b/example/button.go @@ -5,49 +5,43 @@ import ( Blackprint "github.com/blackprint/engine-go/blackprint" "github.com/blackprint/engine-go/engine" - "github.com/blackprint/engine-go/types" ) // ============ type ButtonSimple struct { - *engine.Node + *engine.EmbedNode } type ButtonSimpleIFace struct { - *engine.Interface + *engine.EmbedInterface } func (iface *ButtonSimpleIFace) Clicked(ev any) { log.Printf("\x1b[1m\x1b[33mButton\\Simple:\x1b[0m \x1b[33mI got '%d', time to trigger to the other node\x1b[0m\n", ev) - iface.Node.(*ButtonSimple).Output["Clicked"].Set(ev) + iface.Node.Output["Clicked"].Set(ev) } // This will be called from example.go -func RegisterButton() { - ButtonSimpleOutput := &engine.NodePortTemplate{ - "Clicked": types.Function, - } - - Blackprint.RegisterNode("Example/Button/Simple", func(instance *engine.Instance) any { - node := &ButtonSimple{ - Node: &engine.Node{ - Instance: instance, - - // Node's Output Port Template - TOutput: ButtonSimpleOutput, - }, - } - - iface := node.SetInterface("BPIC/Example/Button").(*ButtonSimpleIFace) - iface.Title = "Button" - - return node - }) - - Blackprint.RegisterInterface("BPIC/Example/Button", func(node any) any { - // node_ := node.(ButtonSimple) - return &ButtonSimpleIFace{ - Interface: &engine.Interface{}, - } - }) +func init() { + Blackprint.RegisterNode("Example/Button/Simple", &engine.NodeMetadata{ + Output: engine.NodePortTemplate{}, + Input: engine.NodePortTemplate{}, + }, + func(instance *engine.Instance) *engine.Node { + node := &engine.Node{ + Embed: &ButtonSimple{}, + } + + iface := node.SetInterface("BPIC/Example/Button") + iface.Title = "Button" + + return node + }) + + Blackprint.RegisterInterface("BPIC/Example/Button", + func(node *engine.Node) *engine.Interface { + return &engine.Interface{ + Embed: &ButtonSimpleIFace{}, + } + }) } diff --git a/example/example.go b/example/example.go deleted file mode 100644 index ebbd126..0000000 --- a/example/example.go +++ /dev/null @@ -1,8 +0,0 @@ -package example - -func init() { - RegisterButton() - RegisterDisplay() - RegisterInput() - RegisterMath() -} diff --git a/example/example_test.go b/example/example_test.go index 3e24be8..c5a04c5 100644 --- a/example/example_test.go +++ b/example/example_test.go @@ -11,7 +11,7 @@ import ( // for benchmarking var instance *engine.Instance -var input *InputSimpleIFace +var input *engine.Interface func TestMain(m *testing.M) { log.SetFlags(0) @@ -28,20 +28,20 @@ func TestMain(m *testing.M) { // Because Golang lack of getter and setter, We need to get or set like calling a function // Anyway.. lets to run something :) - button := instance.Iface["myButton"].(*ButtonSimpleIFace) + button := instance.Iface["myButton"].Embed.(*ButtonSimpleIFace) log.Println("\n>> I'm clicking the button") button.Clicked(123) - logger := instance.Iface["myLogger"].(*LoggerIFace) + logger := instance.Iface["myLogger"].Embed.(*LoggerIFace) log.Println("\n>> I got the output value: " + logger.Log().(string)) log.Println("\n>> I'm writing something to the input box") - input = instance.Iface["myInput"].(*InputSimpleIFace) + input = instance.Iface["myInput"] input.Data["value"].Set("hello wrold") // you can also use getNodes if you haven't set the ID - myLogger := instance.GetNodes("Example/Display/Logger")[0].(*LoggerNode).Iface.(*LoggerIFace) + myLogger := instance.GetNodes("Example/Display/Logger")[0].Embed.(*LoggerIFace) log.Println("\n>> I got the output value: " + myLogger.Log().(string)) } diff --git a/example/input.go b/example/input.go index b0fc4af..d9e0ea6 100644 --- a/example/input.go +++ b/example/input.go @@ -10,32 +10,32 @@ import ( // ============ type InputSimple struct { - *engine.Node + *engine.EmbedNode } // Bring value from imported iface to node output -func (node *InputSimple) Imported() { - val := node.Iface.(*InputSimpleIFace).Data["value"].Get() +func (this *InputSimple) Imported(map[string]any) { + val := this.Iface.Data["value"].Get() if val != nil { log.Printf("\x1b[1m\x1b[33mInput\\Simple:\x1b[0m \x1b[33mSaved data as output: %s\x1b[0m\n", val) } - node.Output["Value"].Set(val) + this.Node.Output["Value"].Set(val) } type InputSimpleIFace struct { - *engine.Interface + *engine.EmbedInterface } -func (iface *InputSimpleIFace) Changed(val any) { +func (this *InputSimpleIFace) Changed(val any) { // This node still being imported - if iface.Importing != false { + if this.Iface.Importing != false { return } log.Printf("\x1b[1m\x1b[33mInput\\Simple:\x1b[0m \x1b[33mThe input box have new value: %s\x1b[0m\n", val) - node := iface.Node.(*InputSimple) + node := this.Node node.Output["Value"].Set(val) // This will call every connected node @@ -57,38 +57,34 @@ func (gs *MyData) Get() any { } // This will be called from example.go -func RegisterInput() { - Blackprint.RegisterNode("Example/Input/Simple", func(instance *engine.Instance) any { - node := &InputSimple{ - Node: &engine.Node{ +func init() { + Blackprint.RegisterNode("Example/Input/Simple", &engine.NodeMetadata{ + Output: engine.NodePortTemplate{ + "Changed": types.Function, + "Value": types.String, + }, + }, + func(instance *engine.Instance) *engine.Node { + node := &engine.Node{ Instance: instance, + Embed: &InputSimple{}, + } - // Node's Output Port Template - TOutput: engine.NodePortTemplate{ - "Changed": types.Function, - "Value": types.String, - }, - }, - } - - iface := node.SetInterface("BPIC/Example/Input").(*InputSimpleIFace) - iface.Title = "Input" - - return node - }) + iface := node.SetInterface("BPIC/Example/Input") + iface.Title = "Input" - Blackprint.RegisterInterface("BPIC/Example/Input", func(node_ any) any { - // node := node_.(InputSimple) + return node + }) - var iface *InputSimpleIFace - iface = &InputSimpleIFace{ - Interface: &engine.Interface{ + Blackprint.RegisterInterface("BPIC/Example/Input", + func(node *engine.Node) *engine.Interface { + iface := &engine.Interface{ Data: engine.InterfaceData{ "value": &MyData{val: "..."}, }, - }, - } + Embed: &InputSimpleIFace{}, + } - return iface - }) + return iface + }) } diff --git a/example/logger.go b/example/logger.go index cd28dbc..fba971a 100644 --- a/example/logger.go +++ b/example/logger.go @@ -7,48 +7,44 @@ import ( Blackprint "github.com/blackprint/engine-go/blackprint" "github.com/blackprint/engine-go/engine" + "github.com/blackprint/engine-go/types" ) -// This will be called from example.go -func RegisterDisplay() { - RegisterLogger() -} - // ============ type LoggerNode struct { - *engine.Node + *engine.EmbedNode } type LoggerIFace struct { - *engine.Interface + *engine.EmbedInterface log string } -func (iface *LoggerIFace) Init() { +func (this *LoggerIFace) Init() { refreshLogger := func(val any) { if val == nil { val = "nil" - iface.Log(val) + this.Log(val) } else { types := reflect.TypeOf(val).Kind() if types == reflect.String || types == reflect.Int64 || types == reflect.Float64 { - iface.Log(val) + this.Log(val) } else { byte_, _ := json.Marshal(val) - iface.Log(string(byte_)) // ToDo, convert any object to JSON string + this.Log(string(byte_)) // ToDo, convert any object to JSON string } } } - node := iface.Node.(*LoggerNode) + node := this.Node // Let's show data after new cable was connected or disconnected - iface.On("cable.connect cable.disconnect", func(_cable any) { + this.Iface.On("cable.connect cable.disconnect", func(_cable any) { log.Printf("\x1b[1m\x1b[33mDisplay\\Logger:\x1b[0m \x1b[33mA cable was changed on Logger, now refresing the input element\x1b[0m\n") refreshLogger(node.Input["Any"].Get()) }) - iface.Input["Any"].On("value", func(_port any) { + this.Iface.Input["Any"].On("value", func(_port any) { port := _port.(*engine.Port) log.Printf("\x1b[1m\x1b[33mDisplay\\Logger:\x1b[0m \x1b[33mI connected to %s (port %s), that have new value: %v\x1b[0m\n", port.Iface.Title, port.Name, port.Value) @@ -68,29 +64,26 @@ func (iface *LoggerIFace) Log(val ...any) any { return nil } -func RegisterLogger() { - Blackprint.RegisterNode("Example/Display/Logger", func(instance *engine.Instance) any { - node := &LoggerNode{ - Node: &engine.Node{ +func init() { + Blackprint.RegisterNode("Example/Display/Logger", &engine.NodeMetadata{ + Input: engine.NodePortTemplate{ + "Any": engine.Ports.ArrayOf(types.Any), // nil => Any + }, + }, + func(instance *engine.Instance) *engine.Node { + node := &engine.Node{ Instance: instance, + Embed: &LoggerNode{}, + } - // Node's Input Port Template - TInput: engine.NodePortTemplate{ - "Any": engine.Ports.ArrayOf(reflect.Interface), // nil => Any - }, - }, - } - - iface := node.SetInterface("BPIC/Example/Display/Logger").(*LoggerIFace) - iface.Title = "Logger" + iface := node.SetInterface("BPIC/Example/Display/Logger") + iface.Title = "Logger" - return node - }) + return node + }) - Blackprint.RegisterInterface("BPIC/Example/Display/Logger", func(node_ any) any { - // node := node_.(LoggerNode) - return &LoggerIFace{ - Interface: &engine.Interface{}, - } - }) + Blackprint.RegisterInterface("BPIC/Example/Display/Logger", + func(node *engine.Node) *engine.Interface { + return &engine.Interface{Embed: &LoggerIFace{}} + }) } diff --git a/example/math.go b/example/math.go index 6bff003..9727320 100644 --- a/example/math.go +++ b/example/math.go @@ -10,116 +10,104 @@ import ( "github.com/blackprint/engine-go/types" ) -// This will be called from example.go -func RegisterMath() { - RegisterMathMultiply() - RegisterMathRandom() -} - -// ============ +// ============ MathMultiple Node ============ type MathMultiple struct { - engine.Node + engine.EmbedNode } // Your own processing mechanism -func (node *MathMultiple) Multiply() int { - log.Printf("\x1b[1m\x1b[33mMath\\Multiply:\x1b[0m \x1b[33mMultiplying %d with %d\x1b[0m\n", node.Input["A"].Get().(int), node.Input["B"].Get().(int)) - return node.Input["A"].Get().(int) * node.Input["B"].Get().(int) +func (this *MathMultiple) Multiply() int { + log.Printf("\x1b[1m\x1b[33mMath\\Multiply:\x1b[0m \x1b[33mMultiplying %d with %d\x1b[0m\n", this.Node.Input["A"].Get().(int), this.Node.Input["B"].Get().(int)) + return this.Node.Input["A"].Get().(int) * this.Node.Input["B"].Get().(int) } // When any output value from other node are updated // Let's immediately change current node result -func (node *MathMultiple) Update(cable *engine.Cable) { - node.Output["Result"].Set(node.Multiply()) +func (this *MathMultiple) Update(cable *engine.Cable) { + this.Node.Output["Result"].Set(this.Multiply()) } -func RegisterMathMultiply() { - Blackprint.RegisterNode("Example/Math/Multiply", func(instance *engine.Instance) any { - var node MathMultiple - node = MathMultiple{ - Node: engine.Node{ +func init() { + Blackprint.RegisterNode("Example/Math/Multiply", &engine.NodeMetadata{ + Input: engine.NodePortTemplate{ + "Exec": engine.Ports.Trigger(func(port *engine.Port) { + port.Iface.Node.Output["Result"].Set(port.Iface.Node.Embed.(*MathMultiple).Multiply()) + log.Printf("\x1b[1m\x1b[33mMath\\Multiply:\x1b[0m \x1b[33mResult has been set: %d\x1b[0m\n", port.Iface.Node.Output["Result"].Get()) + }), + "A": types.Int, + "B": types.Any, + }, + + Output: engine.NodePortTemplate{ + "Result": types.Int, + }, + }, + func(instance *engine.Instance) *engine.Node { + node := &engine.Node{ Instance: instance, + Embed: &MathMultiple{}, + } - // Node's Input Port Template - TInput: engine.NodePortTemplate{ - "Exec": engine.Ports.Trigger(func(port *engine.Port) { - node.Output["Result"].Set(node.Multiply()) - log.Printf("\x1b[1m\x1b[33mMath\\Multiply:\x1b[0m \x1b[33mResult has been set: %d\x1b[0m\n", node.Output["Result"].Get()) - }), - "A": types.Int, - "B": types.Any, - }, - - // Node's Output Port Template - TOutput: engine.NodePortTemplate{ - "Result": types.Int, - }, - }, - } - - iface := node.SetInterface().(*engine.Interface) // default interface - iface.Title = "Multiply" - - node.On("cable.connect", func(event any) { - ev := event.(engine.CableEvent) - log.Printf("\x1b[1m\x1b[33mMath\\Multiply:\x1b[0m \x1b[33mCable connected from %s (%s) to %s (%s)\x1b[0m\n", ev.Port.Iface.Title, ev.Port.Name, ev.Target.Iface.Title, ev.Target.Name) - }) + iface := node.SetInterface() + iface.Title = "Multiply" + + iface.On("cable.connect", func(event any) { + ev := event.(engine.CableEvent) + log.Printf("\x1b[1m\x1b[33mMath\\Multiply:\x1b[0m \x1b[33mCable connected from %s (%s) to %s (%s)\x1b[0m\n", ev.Port.Iface.Title, ev.Port.Name, ev.Target.Iface.Title, ev.Target.Name) + }) - return &node - }) + return node + }) } -// ============ +// ============ MathRandom Node ============ type MathRandom struct { - engine.Node + engine.EmbedNode Executed bool } // When the connected node is requesting for the output value -func (node *MathRandom) Request(port *engine.Port, iface_ any) bool { +func (this *MathRandom) Request(cable *engine.Cable) { // Only run once this node never been executed // Return false if no value was changed - if node.Executed == true { - return false + if this.Executed == true { + return } - iface := iface_.(*engine.Interface) - log.Printf("\x1b[1m\x1b[33mMath\\Random:\x1b[0m \x1b[33mValue request for port: %s, from node: %s\x1b[0m\n", port.Name, iface.Title) + log.Printf("\x1b[1m\x1b[33mMath\\Random:\x1b[0m \x1b[33mValue request for port: %s, from node: %s\x1b[0m\n", cable.Output.Name, cable.Input.Iface.Title) // Let's create the value for him - node.Input["Re-seed"].Call() + this.Node.Input["Re-seed"].Call() - return true + return } -func RegisterMathRandom() { - Blackprint.RegisterNode("Example/Math/Random", func(instance *engine.Instance) any { - var node MathRandom - node = MathRandom{ - Executed: false, - Node: engine.Node{ +func init() { + Blackprint.RegisterNode("Example/Math/Random", &engine.NodeMetadata{ + Input: engine.NodePortTemplate{ + "Re-seed": engine.Ports.Trigger(func(port *engine.Port) { + node := port.Iface.Node + node.Embed.(*MathRandom).Executed = true + + byt := make([]byte, 2) + rand.Read(byt) + node.Output["Out"].Set(int(binary.BigEndian.Uint16(byt[:])) % 100) + }), + }, + + Output: engine.NodePortTemplate{ + "Out": types.Int, + }, + }, + func(instance *engine.Instance) *engine.Node { + node := &engine.Node{ Instance: instance, + Embed: &MathRandom{}, + } + + iface := node.SetInterface() + iface.Title = "Random" - // Node's Input Port Template - TInput: engine.NodePortTemplate{ - "Re-seed": engine.Ports.Trigger(func(port *engine.Port) { - node.Executed = true - byt := make([]byte, 2) - rand.Read(byt) - node.Output["Out"].Set(int(binary.BigEndian.Uint16(byt[:])) % 100) - }), - }, - - // Node's Output Port Template - TOutput: engine.NodePortTemplate{ - "Out": types.Int, - }, - }, - } - - iface := node.SetInterface().(*engine.Interface) // default interface - iface.Title = "Random" - - return &node - }) + return node + }) } From 04c2761d30c418bd86f4ebeaa4f656021c8210e4 Mon Sep 17 00:00:00 2001 From: StefansArya Date: Fri, 9 Sep 2022 16:18:57 +0700 Subject: [PATCH 10/15] Fix some error --- blackprint/nodesBPFunction.go | 108 ++++++++++----------- blackprint/nodesBPVariable.go | 172 +++++++++++++++++---------------- blackprint/nodesEnvironment.go | 116 ++++++++++++---------- blackprint/nodesFnPortVar.go | 163 ++++++++++++++++--------------- engine/bpVar.go | 6 +- engine/cable.go | 17 ++-- engine/engine.go | 50 +++++----- engine/interface.go | 7 +- engine/node.go | 23 ++--- engine/nodesBPFunction.go | 47 +++++---- engine/port.go | 18 ++-- engine/portFeature.go | 4 +- engine/portGetterSetter.go | 8 +- engine/routePort.go | 14 +-- 14 files changed, 392 insertions(+), 361 deletions(-) diff --git a/blackprint/nodesBPFunction.go b/blackprint/nodesBPFunction.go index 0044a57..84e99fd 100644 --- a/blackprint/nodesBPFunction.go +++ b/blackprint/nodesBPFunction.go @@ -10,7 +10,7 @@ import ( ) type nodeInput struct { - *engine.Node + *engine.EmbedNode } func (n *nodeInput) imported(data any) { @@ -29,7 +29,7 @@ func (n *nodeInput) request(cable *engine.Cable) { } type nodeOutput struct { - *engine.Node + *engine.EmbedNode } func (n *nodeOutput) imported(data map[string]any) { @@ -62,7 +62,7 @@ func (n *nodeOutput) update(cable *engine.Cable) { } type FnMain struct { - *engine.Interface + *engine.EmbedInterface QImportOnce bool QSave func(any, string, bool) QPortSw_ any @@ -126,7 +126,7 @@ func (f *FnMain) RenamePort(which string, fromName string, toName string) { } type bpFnInOut struct { - *engine.Interface + *engine.EmbedInterface } type addPortRef struct { @@ -256,66 +256,66 @@ func (b *bpFnInOut) deletePort(name string) { } func init() { - RegisterNode("BP/Fn/Input", func(i *engine.Instance) any { - node := &nodeInput{ - Node: &engine.Node{ + RegisterNode("BP/Fn/Input", + func(i *engine.Instance) *engine.Node { + node := &engine.Node{ Instance: i, - }, - } + Embed: &nodeInput{}, + } - iface := node.SetInterface("BPIC/BP/Fn/Input").(*fnInput) - iface.QEnum = nodes.BPFnInput - iface.QProxyInput = true // Port is initialized dynamically - iface.QDynamicPort = true + iface := node.SetInterface("BPIC/BP/Fn/Input") + iface.QEnum = nodes.BPFnInput + iface.QProxyInput = true // Port is initialized dynamically + iface.QDynamicPort = true - iface.Title = "Input" - iface.Type = "bp-fn-input" - iface.QFuncMain = i.QFuncMain - i.QFuncMain.QProxyInput = node + iface.Title = "Input" + iface.(*fnInput).Type = "bp-fn-input" + iface.QFuncMain = i.QFuncMain + i.QFuncMain.QProxyInput = node - return node - }) + return node + }) - RegisterInterface("BPIC/BP/Fn/Input", func(node any) any { - return &bpFnInOut{ - Interface: &engine.Interface{ - Node: node, - }, - } - }) + RegisterInterface("BPIC/BP/Fn/Input", + func(node *engine.Node) *engine.Interface { + return &engine.Interface{ + Node: node, + Embed: &bpFnInOut{}, + } + }) - RegisterNode("BP/Fn/Output", func(i *engine.Instance) any { - node := &bpVarGet{ - Node: &engine.Node{ + RegisterNode("BP/Fn/Output", + func(i *engine.Instance) *engine.Node { + node := &engine.Node{ Instance: i, - }, - } + Embed: &bpVarGet{}, + } - iface := node.SetInterface("BPIC/BP/Fn/Output").(*fnOutput) - iface.QEnum = nodes.BPFnOutput - iface.QDynamicPort = true // Port is initialized dynamically + iface := node.SetInterface("BPIC/BP/Fn/Output") + iface.QEnum = nodes.BPFnOutput + iface.QDynamicPort = true // Port is initialized dynamically - iface.Title = "Output" - iface.Type = "bp-fn-output" - iface.QFuncMain = i.QFuncMain - i.QFuncMain.QProxyOutput = node + iface.Title = "Output" + iface.(*fnOutput).Type = "bp-fn-output" + iface.QFuncMain = i.QFuncMain + i.QFuncMain.QProxyOutput = node - return node - }) + return node + }) - RegisterInterface("BPIC/BP/Fn/Output", func(node any) any { - return &bpFnInOut{ - Interface: &engine.Interface{ - Node: node, - }, - } - }) + RegisterInterface("BPIC/BP/Fn/Output", + func(node *engine.Node) *engine.Interface { + return &engine.Interface{ + Node: node, + Embed: &bpFnInOut{}, + } + }) - RegisterInterface("BPIC/BP/Fn/Main", func(node any) any { - return &FnMain{ - Interface: &engine.Interface{ - Node: node, - }, - } - }) + RegisterInterface("BPIC/BP/Fn/Main", + func(node *engine.Node) *engine.Interface { + return &engine.Interface{ + Node: node, + Embed: &FnMain{}, + } + }) } diff --git a/blackprint/nodesBPVariable.go b/blackprint/nodesBPVariable.go index 110e4ce..6ccedd9 100644 --- a/blackprint/nodesBPVariable.go +++ b/blackprint/nodesBPVariable.go @@ -10,18 +10,20 @@ import ( ) type bpVarSet struct { - *engine.Node + *engine.EmbedNode } type bpVarGet struct { - *engine.Node + *engine.EmbedNode } func (b *bpVarSet) Update(c *engine.Cable) { - b.Iface.QBpVarRef.Value.Set(b.Input["Val"].Get()) + b.Iface.QBpVarRef.Value.Set(b.Node.Input["Val"].Get()) } type bpVarGetSet struct { - *engine.Interface + *engine.EmbedInterface + Type string + QBpVarRef *engine.BPVariable QOnChanged func(*engine.Port) } @@ -39,14 +41,14 @@ func (b *bpVarGetSet) Imported(data map[string]any) { } func (b *bpVarGetSet) ChangeVar(name string, scopeId int) map[string]*engine.BPVariable { - if _, exist := b.Data["name"]; exist { + if _, exist := b.Iface.Data["name"]; exist { panic("Can't change variable node that already be initialized") } - b.Data["name"] = &engine.GetterSetter{Value: name} - b.Data["scope"] = &engine.GetterSetter{Value: scopeId} + b.Iface.Data["name"] = &engine.GetterSetter{Value: name} + b.Iface.Data["scope"] = &engine.GetterSetter{Value: scopeId} - thisInstance := b.Node.Instance.(*engine.Instance) + thisInstance := b.Node.Instance funcInstance := thisInstance.QFuncMain if funcInstance == nil { funcInstance.Node.QFuncInstance @@ -114,14 +116,14 @@ func (b *bpVarGetSet) Destroy() { return } - temp.Used = utils.RemoveItemAny(temp.Used, b) + temp.Used = utils.RemoveItem(temp.Used, b.Iface) listener := b.QBpVarRef.Listener if listener == nil { return } - b.QBpVarRef.Listener = utils.RemoveItemAny(listener, b) + b.QBpVarRef.Listener = utils.RemoveItem(listener, b.Iface) } type iVarSet struct { @@ -136,7 +138,7 @@ func (b *iVarSet) UseType(port *engine.Port) { } func (b *iVarSet) ChangeVar(name string, scopeId int) { - if _, exist := b.Data["name"]; exist { + if _, exist := b.Iface.Data["name"]; exist { panic("Can't change variable node that already be initialized") } @@ -145,9 +147,9 @@ func (b *iVarSet) ChangeVar(name string, scopeId int) { } scope := b.bpVarGetSet.ChangeVar(name, scopeId) - b.Title = "Get " + name + b.Iface.Title = "Get " + name - temp := scope[b.Data["name"].Get().(string)] + temp := scope[b.Iface.Data["name"].Get().(string)] b.QBpVarRef = temp if temp.Type == 0 { // Type not set return @@ -160,12 +162,12 @@ func (b *iVarSet) QReinitPort() *engine.Port { temp := b.QBpVarRef node := b.Node - if b.Output["Val"] != nil { - node.DeletePort("Val") + if b.Iface.Output["Val"] != nil { + node.DeletePort("output", "Val") } - ref := b.Node.Output.(map[string]*engine.PortOutputGetterSetter) - b.Node.CreatePort("Val", temp.Type) + ref := b.Node.Output + b.Node.CreatePort("output", "Val", temp.Type) if temp.Type == types.Function { b.QEventListen = "call" @@ -180,7 +182,7 @@ func (b *iVarSet) QReinitPort() *engine.Port { } temp.On(b.QEventListen, b.QOnChanged) - return b.Output["Val"] + return b.Iface.Output["Val"] } func (b *iVarSet) Destroy() { @@ -203,9 +205,9 @@ func (b *iVarGet) UseType(port *engine.Port) { func (b *iVarGet) ChangeVar(name string, scopeId int) { scope := b.bpVarGetSet.ChangeVar(name, scopeId) - b.Title = "Set " + name + b.Iface.Title = "Set " + name - temp := scope[b.Data["name"].Get().(string)] + temp := scope[b.Iface.Data["name"].Get().(string)] b.QBpVarRef = temp if temp.Type == 0 { // Type not set return @@ -215,7 +217,7 @@ func (b *iVarGet) ChangeVar(name string, scopeId int) { } func (b *iVarGet) QReinitPort() *engine.Port { - input := b.Input + input := b.Iface.Input node := b.Node temp := b.QBpVarRef @@ -231,73 +233,77 @@ func (b *iVarGet) QReinitPort() *engine.Port { node.CreatePort("Input", "Val", temp.Type) } - return b.Input["Val"] + return input["Val"] } func init() { - RegisterNode("BP/Var/Set", func(i *engine.Instance) any { - node := &bpVarSet{ - Node: &engine.Node{ + RegisterNode("BP/Var/Set", &engine.NodeMetadata{ + Input: engine.NodePortTemplate{}, + }, + func(i *engine.Instance) *engine.Node { + node := &engine.Node{ Instance: i, - }, - } - - iface := node.SetInterface("BPIC/BP/Var/Set").(*iVarSet) - - // Specify data field from here to make it enumerable and exportable - iface.Data = engine.InterfaceData{ - "name": &engine.GetterSetter{Value: ""}, - "scope": &engine.GetterSetter{Value: engine.VarScopePublic}, - } - - iface.Title = "VarSet" - iface.Type = "bp-var-set" - iface.QEnum = nodes.BPVarSet - iface.QDynamicPort = true - - return node - }) - - RegisterInterface("BPIC/BP/Var/Get", func(node any) any { - return &iVarGet{ - bpVarGetSet: &bpVarGetSet{ - Interface: &engine.Interface{ - Node: node, + Embed: &bpVarSet{}, + } + + iface := node.SetInterface("BPIC/BP/Var/Set") + + // Specify data field from here to make it enumerable and exportable + iface.Data = engine.InterfaceData{ + "name": &engine.GetterSetter{Value: ""}, + "scope": &engine.GetterSetter{Value: engine.VarScopePublic}, + } + + iface.Title = "VarSet" + iface.Embed.(*iVarSet).Type = "bp-var-set" + iface.QEnum = nodes.BPVarSet + iface.QDynamicPort = true + + return node + }) + + RegisterInterface("BPIC/BP/Var/Get", + func(node *engine.Node) *engine.Interface { + return &engine.Interface{ + Node: node, + Embed: &iVarGet{ + bpVarGetSet: &bpVarGetSet{}, }, - }, - } - }) - - RegisterNode("BP/Var/Get", func(i *engine.Instance) any { - node := &bpVarGet{ - Node: &engine.Node{ + } + }) + + RegisterNode("BP/Var/Get", &engine.NodeMetadata{ + Output: engine.NodePortTemplate{}, + }, + func(i *engine.Instance) *engine.Node { + node := &engine.Node{ Instance: i, - }, - } - - iface := node.SetInterface("BPIC/BP/Var/Get").(*iVarGet) - - // Specify data field from here to make it enumerable and exportable - iface.Data = engine.InterfaceData{ - "name": &engine.GetterSetter{Value: ""}, - "scope": &engine.GetterSetter{Value: engine.VarScopePublic}, - } - - iface.Title = "VarGet" - iface.Type = "bp-var-get" - iface.QEnum = nodes.BPVarGet - iface.QDynamicPort = true - - return node - }) - - RegisterInterface("BPIC/BP/Var/Get", func(node any) any { - return &iVarGet{ - bpVarGetSet: &bpVarGetSet{ - Interface: &engine.Interface{ - Node: node, + Embed: &bpVarGet{}, + } + + iface := node.SetInterface("BPIC/BP/Var/Get") + + // Specify data field from here to make it enumerable and exportable + iface.Data = engine.InterfaceData{ + "name": &engine.GetterSetter{Value: ""}, + "scope": &engine.GetterSetter{Value: engine.VarScopePublic}, + } + + iface.Title = "VarGet" + iface.Embed.(*iVarGet).Type = "bp-var-get" + iface.QEnum = nodes.BPVarGet + iface.QDynamicPort = true + + return node + }) + + RegisterInterface("BPIC/BP/Var/Get", + func(node *engine.Node) *engine.Interface { + return &engine.Interface{ + Node: node, + Embed: &iVarGet{ + bpVarGetSet: &bpVarGetSet{}, }, - }, - } - }) + } + }) } diff --git a/blackprint/nodesEnvironment.go b/blackprint/nodesEnvironment.go index ef1130f..1241399 100644 --- a/blackprint/nodesEnvironment.go +++ b/blackprint/nodesEnvironment.go @@ -3,14 +3,15 @@ package blackprint import ( "github.com/blackprint/engine-go/engine" "github.com/blackprint/engine-go/engine/nodes" + "github.com/blackprint/engine-go/types" ) type bpEnvGet struct { - *engine.Node + *engine.EmbedNode } type bpEnvSet struct { - *engine.Node + *engine.EmbedNode } func (b *bpEnvSet) Update(c *engine.Cable) { @@ -18,7 +19,8 @@ func (b *bpEnvSet) Update(c *engine.Cable) { } type bpEnvGetSet struct { - *engine.Interface + *engine.EmbedInterface + Type string } func (b *bpEnvGetSet) Imported(data map[string]any) { @@ -26,7 +28,7 @@ func (b *bpEnvGetSet) Imported(data map[string]any) { panic("Parameter 'name' is required") } - b.Data["name"].Set(data["name"]) + b.Iface.Data["name"].Set(data["name"]) name := data["name"].(string) if _, exists := Environment.Map[name]; !exists { @@ -44,7 +46,7 @@ func (b *iEnvGet) Imported(data map[string]any) { b.QListener = func(v any) { ev := v.(*engine.EnvironmentEvent) - if ev.Key != b.Data["name"].Get().(string) { + if ev.Key != b.Iface.Data["name"].Get().(string) { return } @@ -52,7 +54,7 @@ func (b *iEnvGet) Imported(data map[string]any) { } Event.On("environment.changed environment.added", b.QListener) - b.Ref.Output["Val"].Set(Environment.Map[b.Data["name"].Get().(string)]) + b.Ref.Output["Val"].Set(Environment.Map[b.Iface.Data["name"].Get().(string)]) } func (b *iEnvGet) Destroy() { @@ -68,65 +70,73 @@ type iEnvSet struct { } func init() { - RegisterNode("BP/Env/Get", func(i *engine.Instance) any { - node := &bpEnvGet{ - Node: &engine.Node{ + RegisterNode("BP/Env/Get", &engine.NodeMetadata{ + Output: engine.NodePortTemplate{ + "Val": types.String, + }, + }, + func(i *engine.Instance) *engine.Node { + node := &engine.Node{ Instance: i, - }, - } + Embed: &bpEnvGet{}, + } - iface := node.SetInterface("BPIC/BP/Env/Get").(*iEnvGet) + iface := node.SetInterface("BPIC/BP/Env/Get") - // Specify data field from here to make it enumerable and exportable - iface.Data = engine.InterfaceData{ - "name": &engine.GetterSetter{Value: ""}, - } + // Specify data field from here to make it enumerable and exportable + iface.Data = engine.InterfaceData{ + "name": &engine.GetterSetter{Value: ""}, + } - iface.Title = "EnvGet" - iface.Type = "bp-env-get" - iface.QEnum = nodes.BPEnvGet + iface.Title = "EnvGet" + iface.Embed.(*iEnvGet).Type = "bp-env-get" + iface.QEnum = nodes.BPEnvGet - return node - }) + return node + }) - RegisterInterface("BPIC/BP/Env/Get", func(node any) any { - return &iEnvGet{ - bpEnvGetSet: &bpEnvGetSet{ - Interface: &engine.Interface{ - Node: node, + RegisterInterface("BPIC/BP/Env/Get", + func(node *engine.Node) *engine.Interface { + return &engine.Interface{ + Node: node, + Embed: &iEnvGet{ + bpEnvGetSet: &bpEnvGetSet{}, }, - }, - } - }) - - RegisterNode("BP/Env/Set", func(i *engine.Instance) any { - node := &bpEnvSet{ - Node: &engine.Node{ + } + }) + + RegisterNode("BP/Env/Set", &engine.NodeMetadata{ + Input: engine.NodePortTemplate{ + "Val": types.String, + }, + }, + func(i *engine.Instance) *engine.Node { + node := &engine.Node{ Instance: i, - }, - } + Embed: &bpEnvSet{}, + } - iface := node.SetInterface("BPIC/BP/Env/Set").(*iEnvSet) + iface := node.SetInterface("BPIC/BP/Env/Set") - // Specify data field from here to make it enumerable and exportable - iface.Data = engine.InterfaceData{ - "name": &engine.GetterSetter{Value: ""}, - } + // Specify data field from here to make it enumerable and exportable + iface.Data = engine.InterfaceData{ + "name": &engine.GetterSetter{Value: ""}, + } - iface.Title = "EnvSet" - iface.Type = "bp-env-set" - iface.QEnum = nodes.BPEnvSet + iface.Title = "EnvSet" + iface.Embed.(*iEnvSet).Type = "bp-env-set" + iface.QEnum = nodes.BPEnvSet - return node - }) + return node + }) - RegisterInterface("BPIC/BP/Env/Set", func(node any) any { - return &iEnvSet{ - bpEnvGetSet: &bpEnvGetSet{ - Interface: &engine.Interface{ - Node: node, + RegisterInterface("BPIC/BP/Env/Set", + func(node *engine.Node) *engine.Interface { + return &engine.Interface{ + Node: node, + Embed: &iEnvSet{ + bpEnvGetSet: &bpEnvGetSet{}, }, - }, - } - }) + } + }) } diff --git a/blackprint/nodesFnPortVar.go b/blackprint/nodesFnPortVar.go index 76a2ec1..aca2e53 100644 --- a/blackprint/nodesFnPortVar.go +++ b/blackprint/nodesFnPortVar.go @@ -7,12 +7,12 @@ import ( ) type fnVarInput struct { - *engine.Node + *engine.EmbedNode } func (f *fnVarInput) Imported(data map[string]any) { - if f.Routes != nil { - f.Routes.Disabled = true + if f.Node.Routes != nil { + f.Node.Routes.Disabled = true } } @@ -20,11 +20,11 @@ func (f *fnVarInput) Request(cable *engine.Cable) { iface := f.Iface // This will trigger the port to request from outside and assign to this node's port - f.Output["Val"].Set(iface.QParentFunc.Node.Input[iface.Data["name"].Get().(string)]) + f.Node.Output["Val"].Set(iface.QParentFunc.Node.Input[iface.Data["name"].Get().(string)]) } type fnVarOutput struct { - *engine.Node + *engine.EmbedNode } func (f *fnVarOutput) Update(c *engine.Cable) { @@ -33,13 +33,14 @@ func (f *fnVarOutput) Update(c *engine.Cable) { } type bpFnVarInOut struct { - *engine.Interface - OnConnect func(*engine.Cable, *engine.Port) + *engine.EmbedInterface + QOnConnect func(*engine.Cable, *engine.Port) - QParentFunc any // => *engine.Interface - QProxyIface any + QParentFunc *engine.Interface + QProxyIface *engine.Interface QListener func(any) QWaitPortInit func(*engine.Port) + Type string } func (f *bpFnVarInOut) Imported(data map[string]any) { @@ -47,7 +48,7 @@ func (f *bpFnVarInOut) Imported(data map[string]any) { panic("Parameter 'name' is required") } - b.Data["name"].Set(data["name"]) + f.Iface.Data["name"].Set(data["name"]) f.QParentFunc = f.Node.Instance.QFuncMain } @@ -69,8 +70,8 @@ func (f *fnVarInputIface) Imported(data map[string]any) { proxyIface := f.QProxyIface // Run when $this node is being connected with other node - iPort.OnConnect = func(cable *engine.Cable, port *engine.Port) { - iPort.OnConnect = nil + iPort.QOnConnect = func(cable *engine.Cable, port *engine.Port) bool { + iPort.QOnConnect = nil proxyIface.Off("_add."+name, iPort.QWaitPortInit) iPort.QWaitPortInit = nil @@ -83,17 +84,19 @@ func (f *fnVarInputIface) Imported(data map[string]any) { newPort.Name_ = portName newPort.ConnectPort(port) - proxyIface.AddPort(port, name) + proxyIface.Embed.(*bpFnInOut).AddPort(port, name) f.QAddListener() + + return true } // Run when main node is the missing port iPort.QWaitPortInit = func(port *engine.Port) { - iPort.OnConnect = nil + iPort.QOnConnect = nil iPort.QWaitPortInit = nil backup := []*engine.Port{} - for _, val := range f.Output["Val"].Cables { + for _, val := range f.Iface.Output["Val"].Cables { backup = append(backup, val.Input) } @@ -101,7 +104,6 @@ func (f *fnVarInputIface) Imported(data map[string]any) { node.DeletePort("output", "Val") portType := getFnPortType(port, "input", f.QParentFunc, port.Name_) - newPort := node.CreatePort("output", "Val", portType) f.QAddListener() @@ -112,10 +114,10 @@ func (f *fnVarInputIface) Imported(data map[string]any) { proxyIface.Once("_add."+name, iPort.QWaitPortInit) } else { - if _, exist := f.Output["Val"]; !exist { + if _, exist := f.Iface.Output["Val"]; !exist { port := ports[name] portType := getFnPortType(port, "input", f.QParentFunc, port.Name_) - newPort := node.CreatePort("input", "Val", portType) + node.CreatePort("input", "Val", portType) } f.QAddListener() @@ -123,7 +125,7 @@ func (f *fnVarInputIface) Imported(data map[string]any) { } func (f *fnVarInputIface) QAddListener() { - port := f.QProxyIface.Output[f.Data["name"].Get().(string)].(*engine.Port) + port := f.QProxyIface.Output[f.Iface.Data["name"].Get().(string)] if port.Feature == engine.PortTypeTrigger { f.QListener = func(p any) { @@ -159,7 +161,7 @@ func (f *fnVarInputIface) Destroy() { return } - port := f.QProxyIface.Output[f.Data["name"].Get().(string)].(*engine.Port) + port := f.QProxyIface.Output[f.Iface.Data["name"].Get().(string)] if port.Feature == engine.PortTypeTrigger { port.Off("call", f.QListener) } else { @@ -185,8 +187,8 @@ func (f *fnVarOutputIface) Imported(data map[string]any) { proxyIface := f.QParentFunc.QProxyOutput.Iface // Run when $this node is being connected with other node - iPort.OnConnect = func(cable *engine.Cable, port *engine.Port) { - iPort.OnConnect = nil + iPort.QOnConnect = func(cable *engine.Cable, port *engine.Port) bool { + iPort.QOnConnect = nil proxyIface.Off("_add."+name, iPort.QWaitPortInit) iPort.QWaitPortInit = nil @@ -199,16 +201,17 @@ func (f *fnVarOutputIface) Imported(data map[string]any) { newPort.Name_ = portName newPort.ConnectPort(port) - proxyIface.AddPort(port, name) + proxyIface.Embed.(*bpFnInOut).AddPort(port, name) + return true } // Run when main node is the missing port iPort.QWaitPortInit = func(port *engine.Port) { - iPort.OnConnect = nil + iPort.QOnConnect = nil iPort.QWaitPortInit = nil backup := []*engine.Port{} - for _, val := range f.Output["Val"].Cables { + for _, val := range f.Iface.Output["Val"].Cables { backup = append(backup, val.Input) } @@ -216,9 +219,7 @@ func (f *fnVarOutputIface) Imported(data map[string]any) { node.DeletePort("input", "Val") portType := getFnPortType(port, "output", f.QParentFunc, port.Name_) - newPort := node.CreatePort("input", "Val", portType) - f.QAddListener() for _, val := range backup { newPort.ConnectPort(val) @@ -227,20 +228,20 @@ func (f *fnVarOutputIface) Imported(data map[string]any) { proxyIface.Once("_add."+name, iPort.QWaitPortInit) } else { - if _, exist := f.Output["Val"]; !exist { + if _, exist := f.Iface.Output["Val"]; !exist { port := ports[name] portType := getFnPortType(port, "output", f.QParentFunc, port.Name_) - newPort := node.CreatePort("input", "Val", portType) + node.CreatePort("input", "Val", portType) } } } -func getFnPortType(port *engine.Port, which string, parentNode any, ref *engine.RefPortName) any { +func getFnPortType(port *engine.Port, which string, parentNode *engine.BPFunctionNode, ref *engine.RefPortName) any { if port.Feature == engine.PortTypeTrigger { if which == "input" { // Function Input (has output port inside, and input port on main node) return types.Function } else { - return engine.Ports.Trigger(parentNode.Output[ref.Name].CallAll) + return engine.Ports.Trigger(parentNode.Iface.Output[ref.Name].CallAll) } } else { if port.Feature != 0 { @@ -252,67 +253,71 @@ func getFnPortType(port *engine.Port, which string, parentNode any, ref *engine. } func init() { - RegisterNode("BP/FnVar/Input", func(i *engine.Instance) any { - node := &fnVarInput{ - Node: &engine.Node{ + RegisterNode("BP/FnVar/Input", &engine.NodeMetadata{ + Output: engine.NodePortTemplate{}, + }, + func(i *engine.Instance) *engine.Node { + node := &engine.Node{ Instance: i, - }, - } + Embed: &fnVarInput{}, + } - iface := node.SetInterface("BPIC/BP/FnVar/Input").(*fnVarInputIface) + iface := node.SetInterface("BPIC/BP/FnVar/Input") - // Specify data field from here to make it enumerable and exportable - iface.Data = engine.InterfaceData{ - "name": &engine.GetterSetter{Value: ""}, - } + // Specify data field from here to make it enumerable and exportable + iface.Data = engine.InterfaceData{ + "name": &engine.GetterSetter{Value: ""}, + } - iface.Title = "FnInput" - iface.Type = "bp-fnvar-input" - iface.QEnum = nodes.BPFnVarInput - iface.QDynamicPort = true + iface.Title = "FnInput" + iface.Embed.(*fnVarInputIface).Type = "bp-fnvar-input" + iface.QEnum = nodes.BPFnVarInput + iface.QDynamicPort = true - return node - }) + return node + }) - RegisterInterface("BPIC/BP/FnVar/Input", func(node any) any { - return &fnVarInputIface{ - bpFnVarInOut: &bpFnVarInOut{ - Interface: &engine.Interface{ - Node: node, + RegisterInterface("BPIC/BP/FnVar/Input", + func(node *engine.Node) *engine.Interface { + return &engine.Interface{ + Node: node, + Embed: &fnVarInputIface{ + bpFnVarInOut: &bpFnVarInOut{}, }, - }, - } - }) + } + }) - RegisterNode("BP/FnVar/Output", func(i *engine.Instance) any { - node := &fnVarOutput{ - Node: &engine.Node{ + RegisterNode("BP/FnVar/Output", &engine.NodeMetadata{ + Input: engine.NodePortTemplate{}, + }, + func(i *engine.Instance) *engine.Node { + node := &engine.Node{ Instance: i, - }, - } + Embed: &fnVarOutput{}, + } - iface := node.SetInterface("BPIC/BP/FnVar/Output").(*fnVarOutputIface) + iface := node.SetInterface("BPIC/BP/FnVar/Output") - // Specify data field from here to make it enumerable and exportable - iface.Data = engine.InterfaceData{ - "name": &engine.GetterSetter{Value: ""}, - } + // Specify data field from here to make it enumerable and exportable + iface.Data = engine.InterfaceData{ + "name": &engine.GetterSetter{Value: ""}, + } - iface.Title = "FnOutput" - iface.Type = "bp-fnvar-output" - iface.QEnum = nodes.BPFnVarOutput - iface.QDynamicPort = true + iface.Title = "FnOutput" + iface.Embed.(*fnVarOutputIface).Type = "bp-fnvar-output" + iface.QEnum = nodes.BPFnVarOutput + iface.QDynamicPort = true - return node - }) + return node + }) - RegisterInterface("BPIC/BP/FnVar/Output", func(node any) any { - return &fnVarOutputIface{ - bpFnVarInOut: &bpFnVarInOut{ - Interface: &engine.Interface{ - Node: node, + RegisterInterface("BPIC/BP/FnVar/Output", + func(node *engine.Node) *engine.Interface { + return &engine.Interface{ + Node: node, + Embed: &fnVarOutputIface{ + bpFnVarInOut: &bpFnVarInOut{}, }, - }, - } - }) + } + }) } diff --git a/engine/bpVar.go b/engine/bpVar.go index 07c59e4..fa52f23 100644 --- a/engine/bpVar.go +++ b/engine/bpVar.go @@ -24,14 +24,14 @@ type BPVariable struct { Id string Title string Type reflect.Kind - Used []any // *engine.Interface + Used []*Interface Value bpVarValue - Listener []any // *engine.Interface + Listener []*Interface } func (b *BPVariable) Destroy() { for _, iface := range b.Used { - ins := (iface.Node).Instance.(*Instance) + ins := iface.Node.Instance ins.DeleteNode(iface) } diff --git a/engine/cable.go b/engine/cable.go index c054596..d185703 100644 --- a/engine/cable.go +++ b/engine/cable.go @@ -17,6 +17,7 @@ type Cable struct { IsRoute bool Connected bool QEvDisconnected bool + QGhost bool } type CableEvent struct { @@ -94,14 +95,14 @@ func (c *Cable) Disconnect(which_ ...*Port) { // which = port if c.IsRoute { // ToDo: simplify, use 'which' instead of check all if c.Output.Cables != nil { c.Output.Cables = c.Output.Cables[:0] - } else if c.Output.Out == c { - c.Output.Out = nil - } else if c.Input.Out == c { - c.Input.Out = nil + } else if c.Output.RoutePort.Out == c { + c.Output.RoutePort.Out = nil + } else if c.Input.RoutePort.Out == c { + c.Input.RoutePort.Out = nil } - c.Output.In = utils.RemoveItem(c.Output.In, c) - c.Input.In = utils.RemoveItem(c.Input.In, c) + c.Output.RoutePort.In = utils.RemoveItem(c.Output.RoutePort.In, c) + c.Input.RoutePort.In = utils.RemoveItem(c.Input.RoutePort.In, c) c.Connected = false return @@ -127,7 +128,7 @@ func (c *Cable) Disconnect(which_ ...*Port) { // which = port c.Owner.Emit("disconnect", temp) c.Owner.Iface.Emit("cable.disconnect", temp) - ins := c.Owner.Iface.Node.Instance.(*Instance) + ins := c.Owner.Iface.Node.Instance ins.Emit("cable.disconnect", temp) alreadyEmitToInstance = true @@ -153,7 +154,7 @@ func (c *Cable) Disconnect(which_ ...*Port) { // which = port c.Target.Iface.Emit("cable.disconnect", temp) if alreadyEmitToInstance == false { - ins := c.Target.Iface.Node.Instance.(*Instance) + ins := c.Target.Iface.Node.Instance ins.Emit("cable.disconnect", temp) } } diff --git a/engine/engine.go b/engine/engine.go index ea68c0c..3d7100b 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -26,8 +26,10 @@ type Instance struct { Functions map[string]*BPFunction Ref map[string]*referencesShortcut - QFuncMain *BPFunction // => *engine.Interface - QFuncInstance *Instance + QFuncMain *Instance + QFuncInstance *BPFunction + QMainInstance *Instance + QRemote any } func New() *Instance { @@ -99,7 +101,7 @@ type ImportOptions struct { AppendMode bool } -func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inserted []any, err error) { +func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inserted []*Interface, err error) { var data SingleInstanceJSON err = json.Unmarshal(str, &data) @@ -153,7 +155,7 @@ func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inse for _, iface := range ifaces.(nodeList) { iface.I += appendLength - var temp any + var temp *Interface temp, inserted = instance.CreateNode(namespace, iface, inserted) ifaceList[iface.I] = temp @@ -176,7 +178,7 @@ func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inse // If have output connection out := ifaceJSON.Output if out != nil { - Output := *iface.Output.(*map[string]*Port) + Output := iface.Output // Every output port that have connection for portName, ports := range out { @@ -185,14 +187,14 @@ func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inse if linkPortA == nil { if iface.QEnum == nodes.BPFnInput { target := instance.QGetTargetPortType(iface.Node.Instance, "input", ports) - linkPortA = iface.AddPort(target, portName) + linkPortA = iface.Embed.(*bpFnInOut).AddPort(target, portName) if linkPortA == nil { panic(fmt.Sprintf("Can't create output port (%s) for function (%s)", portName, iface.QFuncMain.Node.QFuncInstance.Id)) } } else if iface.QEnum == nodes.BPVarGet { target := instance.QGetTargetPortType(instance, "input", ports) - iface.UseType(target) + iface.Embed.(*iVarGet).UseType(target) linkPortA = iface.Output[portName] } else { panic(fmt.Sprintf("Node port not found for iface (index: %d), with name: %s", ifaceJSON.I, portName)) @@ -205,31 +207,31 @@ func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inse targetNode := ifaceList[target.I] // output can only meet input port - Input := *targetNode.Input.(*map[string]*Port) + Input := targetNode.Input linkPortB := Input[target.Name] if linkPortB == nil { - targetTitle := targetNode.Title.(string) + targetTitle := targetNode.Title if targetNode.QEnum == nodes.BPFnOutput { - linkPortB = targetNode.AddPort(linkPortA, target) + linkPortB = targetNode.Embed.(*bpFnInOut).AddPort(linkPortA, target) if linkPortB == nil { panic(fmt.Sprintf("Can't create output port (%s) for function (%s)", portName, targetNode.QFuncMain.Node.QFuncInstance.Id)) } } else if targetNode.QEnum == nodes.BPVarGet { - targetNode.UseType(target) + targetNode.Embed.(*iVarGet).UseType(target) linkPortB = targetNode.Input[target.Name] - } else if targetNode.Type == types.Route { - linkPortB = targetNode.Node.Routes + } else if linkPortA.Type == types.Route { + linkPortB = targetNode.Node.Routes.Port } else { panic(fmt.Sprintf("Node port not found for %s with name: %s", targetTitle, target.Name)) } } // For Debugging -> - // Title := iface.Title.(string) - // targetTitle := targetNode.Title.(string) + // Title := iface.Title + // targetTitle := targetNode.Title // fmt.Printf("%s.%s => %s.%s\n", Title, linkPortA.Name, targetTitle, linkPortB.Name) // <- For Debugging @@ -264,13 +266,13 @@ type EvNodeDelete struct { Iface any } -func (instance *Instance) DeleteNode(iface any) { - i := utils.IndexOfAny(instance.IfaceList, iface) +func (instance *Instance) DeleteNode(iface *Interface) { + i := utils.IndexOf(instance.IfaceList, iface) if i == -1 { panic("Node to be deleted was not found") } - instance.IfaceList = utils.RemoveItemAtIndexAny(instance.IfaceList, i) + instance.IfaceList = utils.RemoveItemAtIndex(instance.IfaceList, i) eventData := &EvNodeDelete{ Iface: iface, @@ -281,7 +283,7 @@ func (instance *Instance) DeleteNode(iface any) { iface.Destroy() for _, port := range iface.Output { - port.DisconnectAll(instance.QRemote == nil) + port.DisconnectAll() } routes := iface.Node.Routes @@ -349,7 +351,7 @@ func (instance *Instance) GetNodes(namespace string) []*Interface { } // ToDo: sync with JS, when creating function node this still broken -func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes []any) (any, []any) { +func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes []*Interface) (*Interface, []*Interface) { func_ := QNodeList[namespace] var node *Node var isFuncNode bool @@ -382,7 +384,7 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes // *iface: extends engine.Interface iface := node.Iface - if iface == nil || iface.QInitialized.(bool) == false { + if iface == nil || iface.QInitialized == false { panic(namespace + ": Node interface was not found, do you forget to call node.SetInterface() ?") } @@ -433,7 +435,7 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes iface.Init() if nodes != nil { - nodes = append(nodes, node) + nodes = append(nodes, iface) } else { // Init now if not A batch creation node.Init() @@ -555,11 +557,11 @@ type NodeLogEvent struct { Message string } -func (instance *Instance) QLog(iface any, message string) { +func (instance *Instance) QLog(iface *Interface, message string) { evData := NodeLogEvent{ Instance: instance, Iface: iface, - IfaceTitle: iface.Title.(string), + IfaceTitle: iface.Title, Message: message, } diff --git a/engine/interface.go b/engine/interface.go index aeab353..a59a5b1 100644 --- a/engine/interface.go +++ b/engine/interface.go @@ -58,6 +58,11 @@ type Interface struct { QDynamicPort bool QEnum int QBpVarRef *BPVariable + QProxyInput *Node + QProxyOutput *Node + QParentFunc *Interface + QBpInstance *Instance + QBpDestroy bool } // To be overriden @@ -79,7 +84,7 @@ func (iface *Interface) QPrepare(meta *NodeMetadata) { node.Ref = ref iface.Ref = ref - node.Route = &RoutePort{Iface: iface} + node.Routes = &RoutePort{Iface: iface} for i := 0; i < 3; i++ { which := portList[i] diff --git a/engine/node.go b/engine/node.go index 7d30db1..e0ac844 100644 --- a/engine/node.go +++ b/engine/node.go @@ -75,7 +75,6 @@ func (n *Node) SetInterface(namespace ...string) *Interface { iface := &Interface{QInitialized: true, Importing: true} n.Iface = iface - n.CustomEvent = &CustomEvent{} return iface } @@ -90,19 +89,13 @@ func (n *Node) SetInterface(namespace ...string) *Interface { panic(".registerInterface() must return pointer") } - data := iface.Data - if data != nil { - _data := data.(InterfaceData) - - for _, port := range _data { - port.Iface = iface - } + for _, val := range iface.Data { + val.Iface = iface } iface.QInitialized = true iface.Importing = true n.Iface = iface - n.CustomEvent = &CustomEvent{} return iface } @@ -111,11 +104,11 @@ func (n *Node) CreatePort(which string, name string, config_ any) *Port { port := n.Iface.QCreatePort(which, name, config_) if which != "input" { - ifacePort := n.Iface.Input.(map[string]*Port) + ifacePort := n.Iface.Input ifacePort[name] = port n.Input[name] = &PortInputGetterSetter{port: port} } else if which != "output" { - ifacePort := n.Iface.Output.(map[string]*Port) + ifacePort := n.Iface.Output ifacePort[name] = port n.Output[name] = &PortOutputGetterSetter{port: port} } else { @@ -128,9 +121,9 @@ func (n *Node) CreatePort(which string, name string, config_ any) *Port { func (n *Node) RenamePort(which string, name string, to string) { var portList map[string]*Port if which == "input" { - portList = n.Iface.Input.(map[string]*Port) + portList = n.Iface.Input } else if which == "output" { - portList = n.Iface.Output.(map[string]*Port) + portList = n.Iface.Output } else { panic("Can only rename port for 'input' and 'output'") } @@ -163,7 +156,7 @@ func (n *Node) DeletePort(which string, name string) { var port *Port if which != "input" { - ports = n.Iface.Input.(map[string]*Port) + ports = n.Iface.Input port = ports[name] if port == nil { return @@ -171,7 +164,7 @@ func (n *Node) DeletePort(which string, name string) { delete(n.Input, name) } else if which != "output" { - ports = n.Iface.Output.(map[string]*Port) + ports = n.Iface.Output port = ports[name] if port == nil { return diff --git a/engine/nodesBPFunction.go b/engine/nodesBPFunction.go index c062fd6..fae4c1b 100644 --- a/engine/nodesBPFunction.go +++ b/engine/nodesBPFunction.go @@ -10,11 +10,11 @@ import ( // Main function node type BPFunctionNode struct { // Main function node -> BPI/F/{FunctionName} - Node *Node + *EmbedNode } func (b *BPFunctionNode) Init() { - if b.Node.Iface.QImportOnce { + if b.Iface.QImportOnce { b.Iface.QBpFnInit() } } @@ -29,7 +29,7 @@ func (b *BPFunctionNode) Update(cable *Cable) { Output := iface.Node.Output if cable == nil { // Triggered by port route - thisInput := b.Input + thisInput := b.Node.Input // Sync all port value for key, value := range iface.Output { @@ -37,7 +37,7 @@ func (b *BPFunctionNode) Update(cable *Cable) { continue } - Output[key].Set(thisInput[key]()) + Output[key].Set(thisInput[key].Get()) } return @@ -58,14 +58,17 @@ type BPFunction struct { // <= _funcInstance Id string Title string Type int - Used *Interface + Used []*Interface Input *NodePortTemplate Output *NodePortTemplate Structure SingleInstanceJSON - Variables map[string]BPVariable + Variables map[string]*BPVariable PrivateVars []string RootInstance *Instance Node func(*Instance) *Node // Node constructor + + // for internal library use only + QSyncing bool } func (b *BPFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { @@ -78,8 +81,9 @@ func (b *BPFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { nodeInstance.PendingRender = true // Force recalculation for cable position if eventName == "cable.connect" || eventName == "cable.disconnect" { - input := obj.Cable.Input - output := obj.Cable.Output + cable := utils.GetProperty(obj, "Cable").(*Cable) + input := cable.Input + output := cable.Output ifaceList := fromNode.Iface.QBpInstance.IfaceList // Skip event that also triggered when deleting a node @@ -113,7 +117,7 @@ func (b *BPFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { if targetInput == nil { if inputIface.QEnum == nodes.BPFnOutput { - targetInput = inputIface.AddPort(targetOutput, output.Name) + targetInput = inputIface.Embed.(*bpFnInOut).AddPort(targetOutput, output.Name) } else { panic("Output port was not found") } @@ -121,7 +125,7 @@ func (b *BPFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { if targetOutput == nil { if outputIface.QEnum == nodes.BPFnInput { - targetOutput = outputIface.AddPort(targetInput, input.Name) + targetOutput = outputIface.Embed.(*bpFnInOut).AddPort(targetInput, input.Name) } else { panic("Input port was not found") } @@ -140,19 +144,21 @@ func (b *BPFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { } } } else if eventName == "node.created" { - iface := obj.Iface + iface := utils.GetProperty(obj, "Iface").(*Interface) nodeInstance.CreateNode(iface.Namespace, map[string]any{ "data": iface.Data, }) } else if eventName == "node.delete" { - index := utils.IndexOf(fromNode.Iface.QBpInstance.IfaceList, obj.Iface) - if index == false { + objIface := utils.GetProperty(obj, "Iface").(*Interface) + + index := utils.IndexOf(fromNode.Iface.QBpInstance.IfaceList, objIface) + if index == -1 { panic("Failed to get node index") } iface := nodeInstance.IfaceList[index] - if iface.Namespace != obj.Iface.Namespace { - fmt.Println(iface.Namespace + " " + obj.Iface.Namespace) + if iface.Namespace != objIface.Namespace { + fmt.Println(iface.Namespace + " " + objIface.Namespace) panic("Failed to delete node from other function instance") } @@ -163,8 +169,8 @@ func (b *BPFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { } } -func (b *BPFunction) CreateNode(instance *Instance, options map[string]any) (any, []any) { - return instance.CreateNode(b.Node, options) +func (b *BPFunction) CreateNode(instance *Instance, options nodeConfig) (*Interface, []*Interface) { + return instance.CreateNode(b.Node, options, nil) } func (b *BPFunction) CreateVariable(id string, options map[string]any) *BPVariable { @@ -228,10 +234,10 @@ func (b *BPFunction) RenamePort(which string, fromName string, toName string) { var proxyPort string if which == "output" { main = *b.Output - proxyPort = "input" + proxyPort = "Input" } else { main = *b.Input - proxyPort = "output" + proxyPort = "Output" } main[toName] = main[fromName] @@ -247,7 +253,8 @@ func (b *BPFunction) RenamePort(which string, fromName string, toName string) { temp = iface.QProxyInput } - temp.Iface[proxyPort][fromName].Name_.Name = toName + portList := utils.GetProperty(temp.Iface, proxyPort).(map[string]*Port) + portList[fromName].Name_.Name = toName temp.RenamePort(proxyPort, fromName, toName) for _, proxyVar := range iface.BpInstance.IfaceList { diff --git a/engine/port.go b/engine/port.go index 5ba264d..a447df2 100644 --- a/engine/port.go +++ b/engine/port.go @@ -1,6 +1,7 @@ package engine import ( + "fmt" "reflect" "github.com/blackprint/engine-go/engine/nodes" @@ -42,7 +43,8 @@ type Port struct { QGhost bool QFunc func(*Port) QCallAll func() - OnConnect func(*Cable, *Port) + QOnConnect func(*Cable, *Port) bool + QWaitPortInit func(*Port) } /** For internal library use only */ @@ -78,7 +80,8 @@ type PortFeature struct { func (port *Port) QGetPortFeature() *PortFeature { return port.QFeature } -func (port *Port) DisconnectAll(hasRemote bool) { +func (port *Port) DisconnectAll() { + hasRemote := port.Iface.Node.Instance.QRemote == nil for _, cable := range port.Cables { if hasRemote { cable.QEvDisconnected = true @@ -98,7 +101,6 @@ func (port *Port) CreateLinker() getterSetter { } func (port *Port) sync() { - var target *Port skipSync := port.Iface.Node.Routes.Out != nil for _, cable := range port.Cables { @@ -166,11 +168,11 @@ func (port *Port) QCableConnectError(name string, obj *CableErrorEvent, severe b } if obj.Port != nil { - msg += "\nFrom port: " + obj.Port.Name + ") (iface: " + obj.Port.Iface.Namespace + ")\n - Type: " + obj.Port.Source + ") (" + obj.Port.Type + ")" + msg += fmt.Sprintf("\nFrom port: %s (iface: %s)\n - Type: %s) (%s)", obj.Port.Name, obj.Port.Iface.Namespace, obj.Port.Source, obj.Port.Type) } - if obj.Target { - msg += "\nTo port: " + obj.Target.Name + ") (iface: " + obj.Target.Iface.Namespace + "))\n - Type: " + obj.Target.Source + ") (" + obj.Target.Type + "))" + if obj.Target != nil { + msg += fmt.Sprintf("\nTo port: %s (iface: %s)\n - Type: %s) (%s)", obj.Target.Name, obj.Target.Iface.Namespace, obj.Target.Source, obj.Target.Type) } obj.Message = msg @@ -180,7 +182,7 @@ func (port *Port) QCableConnectError(name string, obj *CableErrorEvent, severe b panic(msg + "\n\n") } - instance.emit(name, obj) + instance.Emit(name, obj) } func (port *Port) ConnectCable(cable *Cable) bool { if cable.IsRoute { @@ -199,7 +201,7 @@ func (port *Port) ConnectCable(cable *Cable) bool { return false } - if (port.OnConnect != nil && port.OnConnect(cable, cable.Owner)) || (cable.Owner.OnConnect != nil && cable.Owner.OnConnect(cable, port)) { + if (port.QOnConnect != nil && port.QOnConnect(cable, cable.Owner)) || (cable.Owner.QOnConnect != nil && cable.Owner.QOnConnect(cable, port)) { return false } diff --git a/engine/portFeature.go b/engine/portFeature.go index a3301ea..f406e4a 100644 --- a/engine/portFeature.go +++ b/engine/portFeature.go @@ -53,7 +53,7 @@ func portStructOf_split(port *Port) { port.Splitted = true port.DisconnectAll() - portData := node.Output.(map[string]*PortOutputGetterSetter)[port.Name] + portData := node.Output[port.Name] if portData != nil { portStructOf_handle(port, portData) } @@ -74,7 +74,7 @@ func portStructOf_unsplit(port *Port) { } func portStructOf_handle(port *Port, data any) { - output := port.Iface.Node.Output.(map[string]*PortOutputGetterSetter) + output := port.Iface.Node.Output if data != nil { for key, val := range port.Struct { diff --git a/engine/portGetterSetter.go b/engine/portGetterSetter.go index dc60cc6..85a1de1 100644 --- a/engine/portGetterSetter.go +++ b/engine/portGetterSetter.go @@ -50,7 +50,7 @@ func (gs *PortInputGetterSetter) Get() any { if target.Value == nil { port.Iface.QRequesting = true - target.Iface.Node.Request(target, port.Iface) + target.Iface.Node.Request(temp) port.Iface.QRequesting = false } @@ -86,7 +86,7 @@ func (gs *PortInputGetterSetter) Get() any { if target.Value == nil { port.Iface.QRequesting = true - target.Iface.Node.Request(target, port.Iface) + target.Iface.Node.Request(cable) port.Iface.QRequesting = false } @@ -146,8 +146,8 @@ func (gs *PortOutputGetterSetter) Call() { } // fmt.Println(cable.String()) - if target.QName != nil { - target.Iface.QParentFunc.node.Output[target.QName.Name].Call() + if target.Name_ != nil { + target.Iface.QParentFunc.Node.Output[target.Name_.Name].Call() } else { target.Iface.Node.Input[target.Name].Call() } diff --git a/engine/routePort.go b/engine/routePort.go index a0a4ffb..e322823 100644 --- a/engine/routePort.go +++ b/engine/routePort.go @@ -12,13 +12,13 @@ type RoutePort struct { DisableOut bool Disabled bool IsRoute bool - Iface *engine.Interface + Iface *Interface // for internal library use only QIsPaused bool } -func newRoutePort(iface any) *RoutePort { +func newRoutePort(iface *Interface) *RoutePort { temp := &RoutePort{ Iface: iface, IsRoute: true, @@ -30,7 +30,7 @@ func newRoutePort(iface any) *RoutePort { } // Connect other route port (this .out to other .in port) -func (r *RoutePort) RouteTo(iface any) { +func (r *RoutePort) RouteTo(iface *Interface) { if r.Out != nil { r.Out.Disconnect() } @@ -42,7 +42,7 @@ func (r *RoutePort) RouteTo(iface any) { return } - port := iface.Node.Routes.(*RoutePort) + port := iface.Node.Routes cable := NewCable(r.Port, port.Port) cable.IsRoute = true @@ -80,7 +80,7 @@ func (r *RoutePort) RouteOut() { } if r.Out == nil { - if r.Iface.QEnum.(int) == nodes.BPFnOutput { + if r.Iface.QEnum == nodes.BPFnOutput { node := r.Iface.QFuncMain.Node route := node.Routes.(*RoutePort) route.RouteIn() @@ -94,12 +94,12 @@ func (r *RoutePort) RouteOut() { return } - enum := targetRoute.Iface.QEnum.(int) + enum := targetRoute.Iface.QEnum if enum == 0 { targetRoute.RouteIn(r.Out) } else if enum == nodes.BPFnMain { - routes := targetRoute.Iface.QProxyInput.Routes.(*RoutePort) + routes := targetRoute.Iface.QProxyInput.Routes routes.RouteIn(r.Out) } else if enum == nodes.BPFnOutput { node := targetRoute.Iface.QFuncMain.Node From 629b31e5a5b8dacb5238ec5757531c571ea4fb4a Mon Sep 17 00:00:00 2001 From: StefansArya Date: Fri, 9 Sep 2022 21:37:14 +0700 Subject: [PATCH 11/15] Fix problems and migrate some files into one package --- blackprint/blackprint.go | 5 +- blackprint/nodesBPFunction.go | 321 ------------------ engine/bpVar.go | 13 +- engine/engine.go | 61 ++-- engine/interface.go | 5 +- engine/node.go | 7 +- engine/nodesBPFunction.go | 364 +++++++++++++++++++-- {blackprint => engine}/nodesBPVariable.go | 151 +++++---- {blackprint => engine}/nodesEnvironment.go | 97 +++--- {blackprint => engine}/nodesFnPortVar.go | 129 ++++---- engine/port.go | 6 +- engine/portFeature.go | 4 +- engine/routePort.go | 6 +- example/input.go | 12 +- 14 files changed, 609 insertions(+), 572 deletions(-) delete mode 100644 blackprint/nodesBPFunction.go rename {blackprint => engine}/nodesBPVariable.go (64%) rename {blackprint => engine}/nodesEnvironment.go (52%) rename {blackprint => engine}/nodesFnPortVar.go (72%) diff --git a/blackprint/blackprint.go b/blackprint/blackprint.go index 7ab8b14..bc15e77 100644 --- a/blackprint/blackprint.go +++ b/blackprint/blackprint.go @@ -8,7 +8,10 @@ import ( // The constructor must return pointer (ex: &Node{}) func RegisterNode(namespace string, meta *engine.NodeMetadata, constructor engine.NodeConstructor) { - engine.QNodeList[namespace] = constructor + engine.QNodeList[namespace] = &engine.QNodeRegister{ + Metadata: meta, + Constructor: constructor, + } } // The constructor must return pointer (ex: &any) diff --git a/blackprint/nodesBPFunction.go b/blackprint/nodesBPFunction.go deleted file mode 100644 index 84e99fd..0000000 --- a/blackprint/nodesBPFunction.go +++ /dev/null @@ -1,321 +0,0 @@ -package blackprint - -import ( - "strconv" - "strings" - - "github.com/blackprint/engine-go/engine" - "github.com/blackprint/engine-go/engine/nodes" - "github.com/blackprint/engine-go/types" -) - -type nodeInput struct { - *engine.EmbedNode -} - -func (n *nodeInput) imported(data any) { - input := n.Iface.QFuncMain.Node.QFuncInstance.Input - - for key, value := range input { - n.CreatePort("output", key, value) - } -} - -func (n *nodeInput) request(cable *engine.Cable) { - name := cable.Output.Name - - // This will trigger the port to request from outside and assign to this node's port - n.Output[name].Set(n.Iface.QFuncMain.Node.Input[name].Get()) -} - -type nodeOutput struct { - *engine.EmbedNode -} - -func (n *nodeOutput) imported(data map[string]any) { - output := n.Iface.QFuncMain.Node.QFuncInstance.Output - - for key, value := range output { - n.CreatePort("input", key, value) - } -} - -func (n *nodeOutput) update(cable *engine.Cable) { - iface := n.Iface.QFuncMain - if cable == nil { // Triggered by port route - IOutput := iface.Output - Output := iface.Node.Output - thisInput := n.Input - - // Sync all port value - for key, value := range IOutput { - if value.Type == types.Function { - continue - } - Output[key].Set(thisInput[key].Get()) - } - - return - } - - iface.Node.Output[cable.Input.Name].Set(cable.GetValue()) -} - -type FnMain struct { - *engine.EmbedInterface - QImportOnce bool - QSave func(any, string, bool) - QPortSw_ any -} - -func (f *FnMain) QBpFnInit() { - if f.QImportOnce { - panic("Can't import function more than once") - } - - f.QImportOnce = true - node := f.Node - - f.QBpInstance = engine.New() - bpFunction := node.QFuncInstance - - newInstance := f.QBpInstance - // newInstance.Variables = []; // private for one function - newInstance.SharedVariables = bpFunction.Variables // shared between function - newInstance.Functions = node.Instance.Functions - newInstance.QFuncMain = f - newInstance.QMainInstance = bpFunction.RootInstance - - bpFunction.RefreshPrivateVars(newInstance) - - swallowCopy := make([]any, len(bpFunction.Structure)) - copy(swallowCopy, bpFunction.Structure) - - f.QBpInstance.ImportJSON(swallowCopy) - - // Init port switches - if f.QPortSw_ != nil { - f.QInitPortSwitches(f.QPortSw_) - f.QPortSw_ = nil - - InputIface := f.QProxyInput.Iface - if InputIface.QPortSw_ != nil { - InputIface.QInitPortSwitches(InputIface.QPortSw_) - InputIface.QPortSw_ = nil - } - } - - f.QSave = func(ev any, eventName string, force bool) { - if force || bpFunction.QSyncing { - return - } - - ev.BpFunction = bpFunction - newInstance.QMainInstance.Emit(eventName, ev) - - bpFunction.QSyncing = true - bpFunction.QOnFuncChanges(eventName, ev, f.Node) - bpFunction.QSyncing = false - } - - f.QBpInstance.On("cable.connect cable.disconnect node.created node.delete node.id.changed", f.QSave) -} -func (f *FnMain) RenamePort(which string, fromName string, toName string) { - f.Node.QFuncInstance.RenamePort(which, fromName, toName) - f.QSave(false, "", true) -} - -type bpFnInOut struct { - *engine.EmbedInterface -} - -type addPortRef struct { - Node *engine.Node - Port *engine.Port -} - -func (b *bpFnInOut) AddPort(port *engine.Port, customName string) *engine.Port { - if port == nil { - panic("Can't set type with nil") - } - - if strings.HasPrefix(port.Iface.Namespace, "BP/Fn") { - panic("Function Input can't be connected directly to Output") - } - - var name string - if port.Name_ != nil { - name = port.Name_.Name - } else if customName != "" { - name = customName - } else { - name = port.Name - } - - var reff *addPortRef - var portType any - if port.Feature == engine.PortTypeTrigger { - reff = &addPortRef{} - portType = engine.Ports.Trigger(func(*engine.Port) { - reff.Node.Output[reff.Port.Name].Call() - }) - } else { - if port.Feature != 0 { - portType = port.QGetPortFeature() - } else { - portType = port.Type - } - } - - var nodeA *engine.Node - var nodeB *engine.Node - // nodeA, nodeB; // Main (input) -> Input (output), Output (input) -> Main (output) - if b.Type == "bp-fn-input" { // Main (input) -> Input (output) - inc := 1 - for true { - _, exist := b.Output[name] - if !exist { - break - } - - name += strconv.Itoa(inc) - inc++ - } - - nodeA = b.QFuncMain.Node - nodeB = b.Node - nodeA.QFuncInstance.Input[name] = portType - } else { // Output (input) -> Main (output) - inc := 1 - for true { - _, exist := b.Input[name] - if !exist { - break - } - - name += strconv.Itoa(inc) - inc++ - } - - nodeA = b.Node - nodeB = b.QFuncMain.Node - nodeB.QFuncInstance.Output[name] = portType - } - - outputPort := nodeB.CreatePort("output", name, portType) - - var inputPort *engine.Port - if portType == types.Function { - inputPort = nodeA.CreatePort("input", name, engine.Ports.Trigger(outputPort.QCallAll)) - } else { - inputPort = nodeA.CreatePort("input", name, portType) - } - - if reff != nil { - reff.Node = nodeB - reff.Port = inputPort - } - - if b.Type == "bp-fn-input" { - outputPort.Name_ = &RefPortName{Name: name} // When renaming port, this also need to be changed - b.Emit("_add.{name}", outputPort) - - inputPort.On("value", func(ev engine.PortValueEvent) { - outputPort.Iface.Node.Output[outputPort.Name](ev.Cable.Output.Value) - }) - - return outputPort - } - - inputPort.Name_ = &RefPortName{Name: name} // When renaming port, this also need to be changed - b.Emit("_add.{name}", inputPort) - return inputPort -} - -func (b *bpFnInOut) renamePort(fromName string, toName string) { - bpFunction := b.QFuncMain.Node.QFuncInstance - // Main (input) -> Input (output) - if b.Type == "bp-fn-input" { - bpFunction.RenamePort("input", fromName, toName) - } else { // Output (input) -> Main (output) - bpFunction.RenamePort("output", fromName, toName) - } -} - -func (b *bpFnInOut) deletePort(name string) { - funcMainNode := b.QFuncMain.Node - if b.Type == "bp-fn-input" { // Main (input) -> Input (output) - funcMainNode.DeletePort("input", name) - b.Node.DeletePort("output", name) - delete(funcMainNode.QFuncInstance.Input, name) - } else { // Output (input) -> Main (output) - funcMainNode.DeletePort("output", name) - b.Node.DeletePort("input", name) - delete(funcMainNode.QFuncInstance.Output, name) - } -} - -func init() { - RegisterNode("BP/Fn/Input", - func(i *engine.Instance) *engine.Node { - node := &engine.Node{ - Instance: i, - Embed: &nodeInput{}, - } - - iface := node.SetInterface("BPIC/BP/Fn/Input") - iface.QEnum = nodes.BPFnInput - iface.QProxyInput = true // Port is initialized dynamically - iface.QDynamicPort = true - - iface.Title = "Input" - iface.(*fnInput).Type = "bp-fn-input" - iface.QFuncMain = i.QFuncMain - i.QFuncMain.QProxyInput = node - - return node - }) - - RegisterInterface("BPIC/BP/Fn/Input", - func(node *engine.Node) *engine.Interface { - return &engine.Interface{ - Node: node, - Embed: &bpFnInOut{}, - } - }) - - RegisterNode("BP/Fn/Output", - func(i *engine.Instance) *engine.Node { - node := &engine.Node{ - Instance: i, - Embed: &bpVarGet{}, - } - - iface := node.SetInterface("BPIC/BP/Fn/Output") - iface.QEnum = nodes.BPFnOutput - iface.QDynamicPort = true // Port is initialized dynamically - - iface.Title = "Output" - iface.(*fnOutput).Type = "bp-fn-output" - iface.QFuncMain = i.QFuncMain - i.QFuncMain.QProxyOutput = node - - return node - }) - - RegisterInterface("BPIC/BP/Fn/Output", - func(node *engine.Node) *engine.Interface { - return &engine.Interface{ - Node: node, - Embed: &bpFnInOut{}, - } - }) - - RegisterInterface("BPIC/BP/Fn/Main", - func(node *engine.Node) *engine.Interface { - return &engine.Interface{ - Node: node, - Embed: &FnMain{}, - } - }) -} diff --git a/engine/bpVar.go b/engine/bpVar.go index fa52f23..9be1d9e 100644 --- a/engine/bpVar.go +++ b/engine/bpVar.go @@ -21,12 +21,13 @@ func (b *bpVarValue) Set(val any) { // used for instance.CreateVariable type BPVariable struct { *CustomEvent - Id string - Title string - Type reflect.Kind - Used []*Interface - Value bpVarValue - Listener []*Interface + Id string + Title string + Type reflect.Kind + Used []*Interface + Value bpVarValue + Listener []*Interface + FuncInstance *BPFunction // for shared function variables } func (b *BPVariable) Destroy() { diff --git a/engine/engine.go b/engine/engine.go index 3d7100b..f11a911 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -26,10 +26,12 @@ type Instance struct { Functions map[string]*BPFunction Ref map[string]*referencesShortcut - QFuncMain *Instance - QFuncInstance *BPFunction - QMainInstance *Instance - QRemote any + // For internal library use only + SharedVariables map[string]*BPVariable + QFuncMain *Interface + QFuncInstance *BPFunction + QMainInstance *Instance + QRemote any } func New() *Instance { @@ -87,6 +89,7 @@ type getterSetter interface { type GetterSetter struct { Value any + Iface *Interface } func (b *GetterSetter) Get() any { @@ -101,6 +104,11 @@ type ImportOptions struct { AppendMode bool } +type QNodeRegister struct { + Metadata *NodeMetadata + Constructor NodeConstructor +} + func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inserted []*Interface, err error) { var data SingleInstanceJSON @@ -109,6 +117,10 @@ func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inse return } + return instance.ImportJSONParsed(data, options...) +} + +func (instance *Instance) ImportJSONParsed(data SingleInstanceJSON, options ...ImportOptions) (inserted []*Interface, err error) { hasOption := len(options) != 0 options_ := options[0] @@ -187,7 +199,7 @@ func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inse if linkPortA == nil { if iface.QEnum == nodes.BPFnInput { target := instance.QGetTargetPortType(iface.Node.Instance, "input", ports) - linkPortA = iface.Embed.(*bpFnInOut).AddPort(target, portName) + linkPortA = iface.Embed.(*QBpFnInOut).AddPort(target, portName) if linkPortA == nil { panic(fmt.Sprintf("Can't create output port (%s) for function (%s)", portName, iface.QFuncMain.Node.QFuncInstance.Id)) @@ -214,12 +226,13 @@ func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inse targetTitle := targetNode.Title if targetNode.QEnum == nodes.BPFnOutput { - linkPortB = targetNode.Embed.(*bpFnInOut).AddPort(linkPortA, target) + linkPortB = targetNode.Embed.(*QBpFnInOut).AddPort(linkPortA, portName) if linkPortB == nil { panic(fmt.Sprintf("Can't create output port (%s) for function (%s)", portName, targetNode.QFuncMain.Node.QFuncInstance.Id)) } } else if targetNode.QEnum == nodes.BPVarGet { + target := instance.QGetTargetPortType(instance, "input", ports) targetNode.Embed.(*iVarGet).UseType(target) linkPortB = targetNode.Input[target.Name] } else if linkPortA.Type == types.Route { @@ -249,6 +262,7 @@ func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inse } return + } func (instance *Instance) QGetTargetPortType(ins *Instance, which string, targetNodes []nodePortTarget) *Port { @@ -299,9 +313,9 @@ func (instance *Instance) DeleteNode(iface *Interface) { delete(instance.Iface, iface.Id) delete(instance.Ref, iface.Id) - parent := iface.Node.Instance.QFuncMain + parent := iface.Node.Instance.QFuncInstance if parent != nil { - delete(parent.Ref, iface.Id) + delete(parent.RootInstance.Ref, iface.Id) } instance.Emit("node.deleted", eventData) @@ -360,7 +374,7 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes if strings.HasPrefix(namespace, "BPI/F/") { temp := instance.Functions[namespace] if temp != nil { - node = temp.QBuilder() + node = temp.Node(instance) } isFuncNode = true @@ -370,7 +384,7 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes panic("Node nodes for " + namespace + " was not found, maybe .registerNode() haven't being called?") } } else { - node = func_(instance) // func_ from registerNode(namespace, func_) + node = func_.Constructor(instance) // func_ from registerNode(namespace, func_) } // Disable data flow on any node ports @@ -393,7 +407,7 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes // Create the linker between the nodes and the iface if isFuncNode == false { - iface.QPrepare() + iface.QPrepare(func_.Metadata) } if options.Id != "" { @@ -401,9 +415,9 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes instance.Iface[options.Id] = iface instance.Ref[options.Id] = iface.Ref - parent := iface.Node.Instance.QFuncMain + parent := iface.Node.QFuncInstance if parent != nil { - parent.Ref[options.Id] = iface.Ref + parent.RootInstance.Ref[options.Id] = iface.Ref } } @@ -506,23 +520,28 @@ func (instance *Instance) CreateFunction(id string, options any) *BPFunction { Type: 0, // Type not set Structure: structure, RootInstance: instance, + Input: NodePortTemplate{}, + Output: NodePortTemplate{}, + } + + meta := &NodeMetadata{ + Input: temp.Input, + Output: temp.Output, } uniqId := 0 temp.Node = func(ins *Instance) *Node { - ins.QFuncInstance = instance + ins.QFuncInstance = temp node := &Node{ Instance: ins, QFuncInstance: temp, - TInput: temp.Input, - TOutput: temp.Output, } - node.Embed = &BPFunctionNode{Node: node} + node.Embed = &BPFunctionNode{} iface := node.SetInterface("BPIC/BP/Fn/Main") - iface.Type = "function" + iface.Embed.(*BPFunctionNode).Type = "function" iface.QEnum = nodes.BPFnMain iface.Namespace = id iface.Title = title @@ -530,15 +549,15 @@ func (instance *Instance) CreateFunction(id string, options any) *BPFunction { uniqId += 1 iface.uniqId = uniqId - iface.QPrepare() + iface.QPrepare(meta) return node } instance.Functions[id] = temp for _, val := range options_.Vars { - temp.CreateVariable(val, bpFnVarOptions{ - Scope: val, + temp.CreateVariable(val, FnVarOptions{ + Scope: VarScopeShared, }) } diff --git a/engine/interface.go b/engine/interface.go index a59a5b1..12889bc 100644 --- a/engine/interface.go +++ b/engine/interface.go @@ -35,6 +35,7 @@ type Interface struct { *CustomEvent Id string + uniqId int // For BPFunction only I int // index Title string Namespace string @@ -54,7 +55,7 @@ type Interface struct { // for internal library use only QInitialized bool QRequesting bool - QFuncMain *NodesFunctionMain + QFuncMain *Interface QDynamicPort bool QEnum int QBpVarRef *BPVariable @@ -217,7 +218,7 @@ func (iface *Interface) QInitPortSwitches(portSwitches map[string]int) { } // Load saved port data value -func (iface *Interface) QImportInputs(ports map[string]*Port) { +func (iface *Interface) QImportInputs(ports map[string]any) { for key, val := range ports { iface.Input[key].Default = val } diff --git a/engine/node.go b/engine/node.go index e0ac844..b93735c 100644 --- a/engine/node.go +++ b/engine/node.go @@ -41,7 +41,10 @@ type Node struct { Input map[string]*PortInputGetterSetter // Property map[string]getterSetter + // For internal library use only QFuncInstance *BPFunction + RefOutput map[string]*PortOutputGetterSetter + // RefInput map[string]*PortInputGetterSetter } // Proxies, for library only @@ -63,7 +66,7 @@ type NodeConstructor func(*Instance) *Node type InterfaceConstructor func(*Node) *Interface // QNodeList = Private function, for internal library only -var QNodeList = map[string]NodeConstructor{} +var QNodeList = map[string]*QNodeRegister{} // QInterfaceList = Private function, for internal library only var QInterfaceList = map[string]InterfaceConstructor{} @@ -90,7 +93,7 @@ func (n *Node) SetInterface(namespace ...string) *Interface { } for _, val := range iface.Data { - val.Iface = iface + utils.SetProperty(val, "Iface", iface) } iface.QInitialized = true diff --git a/engine/nodesBPFunction.go b/engine/nodesBPFunction.go index fae4c1b..3bf804b 100644 --- a/engine/nodesBPFunction.go +++ b/engine/nodesBPFunction.go @@ -2,6 +2,8 @@ package engine import ( "fmt" + "strconv" + "strings" "github.com/blackprint/engine-go/engine/nodes" "github.com/blackprint/engine-go/types" @@ -11,10 +13,11 @@ import ( // Main function node type BPFunctionNode struct { // Main function node -> BPI/F/{FunctionName} *EmbedNode + Type string } func (b *BPFunctionNode) Init() { - if b.Iface.QImportOnce { + if b.Iface.Embed.(*FnMain).QImportOnce { b.Iface.QBpFnInit() } } @@ -59,8 +62,8 @@ type BPFunction struct { // <= _funcInstance Title string Type int Used []*Interface - Input *NodePortTemplate - Output *NodePortTemplate + Input NodePortTemplate + Output NodePortTemplate Structure SingleInstanceJSON Variables map[string]*BPVariable PrivateVars []string @@ -78,7 +81,7 @@ func (b *BPFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { } nodeInstance := iface_.QBpInstance - nodeInstance.PendingRender = true // Force recalculation for cable position + // nodeInstance.PendingRender = true // Force recalculation for cable position if eventName == "cable.connect" || eventName == "cable.disconnect" { cable := utils.GetProperty(obj, "Cable").(*Cable) @@ -117,7 +120,7 @@ func (b *BPFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { if targetInput == nil { if inputIface.QEnum == nodes.BPFnOutput { - targetInput = inputIface.Embed.(*bpFnInOut).AddPort(targetOutput, output.Name) + targetInput = inputIface.Embed.(*QBpFnInOut).AddPort(targetOutput, output.Name) } else { panic("Output port was not found") } @@ -125,7 +128,7 @@ func (b *BPFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { if targetOutput == nil { if outputIface.QEnum == nodes.BPFnInput { - targetOutput = outputIface.Embed.(*bpFnInOut).AddPort(targetInput, input.Name) + targetOutput = outputIface.Embed.(*QBpFnInOut).AddPort(targetInput, input.Name) } else { panic("Input port was not found") } @@ -145,9 +148,9 @@ func (b *BPFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { } } else if eventName == "node.created" { iface := utils.GetProperty(obj, "Iface").(*Interface) - nodeInstance.CreateNode(iface.Namespace, map[string]any{ - "data": iface.Data, - }) + nodeInstance.CreateNode(iface.Namespace, nodeConfig{ + Data: iface.Data, + }, nil) } else if eventName == "node.delete" { objIface := utils.GetProperty(obj, "Iface").(*Interface) @@ -169,11 +172,15 @@ func (b *BPFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { } } -func (b *BPFunction) CreateNode(instance *Instance, options nodeConfig) (*Interface, []*Interface) { - return instance.CreateNode(b.Node, options, nil) +// func (b *BPFunction) CreateNode(instance *Instance, options nodeConfig) (*Interface, []*Interface) { +// return instance.CreateNode(b.Node, options, nil) +// } + +type FnVarOptions struct { + Scope int } -func (b *BPFunction) CreateVariable(id string, options map[string]any) *BPVariable { +func (b *BPFunction) CreateVariable(id string, options FnVarOptions) *BPVariable { if _, exist := b.Variables[id]; exist { panic("Variable id already exist: id") } @@ -186,7 +193,7 @@ func (b *BPFunction) CreateVariable(id string, options map[string]any) *BPVariab } temp.FuncInstance = b - if options["scope"] == VarScopeShared { + if options.Scope == VarScopeShared { b.Variables[id] = temp } else { b.AddPrivateVars(id) @@ -233,10 +240,10 @@ func (b *BPFunction) RenamePort(which string, fromName string, toName string) { var main NodePortTemplate var proxyPort string if which == "output" { - main = *b.Output + main = b.Output proxyPort = "Input" } else { - main = *b.Input + main = b.Input proxyPort = "Output" } @@ -257,18 +264,18 @@ func (b *BPFunction) RenamePort(which string, fromName string, toName string) { portList[fromName].Name_.Name = toName temp.RenamePort(proxyPort, fromName, toName) - for _, proxyVar := range iface.BpInstance.IfaceList { + for _, proxyVar := range iface.QBpInstance.IfaceList { if (which == "output" && proxyVar.Namespace != "BP/FnVar/Output") || (which == "input" && proxyVar.Namespace != "BP/FnVar/Input") { continue } - if proxyVar.Data.Name != fromName { + if proxyVar.Data["name"].Get() != fromName { continue } - proxyVar.Data.Name = toName + proxyVar.Data["name"].Set(toName) if which == "output" { - proxyVar[proxyPort]["Val"].Name_.Name = toName + proxyVar.Input["Val"].Name_.Name = toName } } } @@ -279,3 +286,322 @@ func (b *BPFunction) Destroy() { iface.Node.Instance.DeleteNode(iface) } } + +type QNodeInput struct { + *EmbedNode +} + +func (n *QNodeInput) imported(data any) { + input := n.Iface.QFuncMain.Node.QFuncInstance.Input + + for key, value := range input { + n.Node.CreatePort("output", key, value) + } +} + +func (n *QNodeInput) request(cable *Cable) { + name := cable.Output.Name + + // This will trigger the port to request from outside and assign to this node's port + n.Node.Output[name].Set(n.Iface.QFuncMain.Node.Input[name].Get()) +} + +type QNodeOutput struct { + *EmbedNode +} + +func (n *QNodeOutput) imported(data map[string]any) { + output := n.Iface.QFuncMain.Node.QFuncInstance.Output + + for key, value := range output { + n.Node.CreatePort("input", key, value) + } +} + +func (n *QNodeOutput) update(cable *Cable) { + iface := n.Iface.QFuncMain + if cable == nil { // Triggered by port route + IOutput := iface.Output + Output := iface.Node.Output + thisInput := n.Node.Input + + // Sync all port value + for key, value := range IOutput { + if value.Type == types.Function { + continue + } + Output[key].Set(thisInput[key].Get()) + } + + return + } + + iface.Node.Output[cable.Input.Name].Set(cable.GetValue()) +} + +type FnMain struct { + *EmbedInterface + QImportOnce bool + QSave func(any, string, bool) + QPortSw_ map[string]int +} + +func (f *FnMain) QBpFnInit() { + if f.QImportOnce { + panic("Can't import function more than once") + } + + f.QImportOnce = true + node := f.Node + + f.Iface.QBpInstance = New() + bpFunction := node.QFuncInstance + + newInstance := f.Iface.QBpInstance + // newInstance.Variables = []; // private for one function + newInstance.SharedVariables = bpFunction.Variables // shared between function + newInstance.Functions = node.Instance.Functions + newInstance.QFuncMain = f.Iface + newInstance.QMainInstance = bpFunction.RootInstance + + bpFunction.RefreshPrivateVars(newInstance) + + // swallowCopy := make([]any, len(bpFunction.Structure)) + // copy(swallowCopy, bpFunction.Structure) + + f.Iface.QBpInstance.ImportJSONParsed(bpFunction.Structure) + + // Init port switches + if f.QPortSw_ != nil { + f.Iface.QInitPortSwitches(f.QPortSw_) + f.QPortSw_ = nil + + InputIface := f.Iface.QProxyInput.Iface + InputIface_ := InputIface.Embed.(*QBpFnInOut) + + if InputIface_.QPortSw_ != nil { + InputIface.QInitPortSwitches(InputIface_.QPortSw_) + InputIface_.QPortSw_ = nil + } + } + + f.QSave = func(ev any, eventName string, force bool) { + if force || bpFunction.QSyncing { + return + } + + // ev.BpFunction = bpFunction + newInstance.QMainInstance.Emit(eventName, ev) + + bpFunction.QSyncing = true + bpFunction.QOnFuncChanges(eventName, ev, f.Node) + bpFunction.QSyncing = false + } + + f.Iface.QBpInstance.On("cable.connect cable.disconnect node.created node.delete node.id.changed", f.QSave) +} +func (f *FnMain) RenamePort(which string, fromName string, toName string) { + f.Node.QFuncInstance.RenamePort(which, fromName, toName) + f.QSave(false, "", true) +} + +type QBpFnInOut struct { + *EmbedInterface + Type string + QPortSw_ map[string]int +} + +type addPortRef struct { + Node *Node + Port *Port +} + +func (b *QBpFnInOut) AddPort(port *Port, customName string) *Port { + if port == nil { + panic("Can't set type with nil") + } + + if strings.HasPrefix(port.Iface.Namespace, "BP/Fn") { + panic("Function Input can't be connected directly to Output") + } + + var name string + if port.Name_ != nil { + name = port.Name_.Name + } else if customName != "" { + name = customName + } else { + name = port.Name + } + + var reff *addPortRef + var portType any + if port.Feature == PortTypeTrigger { + reff = &addPortRef{} + portType = Ports.Trigger(func(*Port) { + reff.Node.Output[reff.Port.Name].Call() + }) + } else { + if port.Feature != 0 { + portType = port.QGetPortFeature() + } else { + portType = port.Type + } + } + + var nodeA *Node + var nodeB *Node + // nodeA, nodeB; // Main (input) -> Input (output), Output (input) -> Main (output) + if b.Type == "bp-fn-input" { // Main (input) -> Input (output) + inc := 1 + for true { + _, exist := b.Iface.Output[name] + if !exist { + break + } + + name += strconv.Itoa(inc) + inc++ + } + + nodeA = b.Iface.QFuncMain.Node + nodeB = b.Node + nodeA.QFuncInstance.Input[name] = portType + } else { // Output (input) -> Main (output) + inc := 1 + for true { + _, exist := b.Iface.Input[name] + if !exist { + break + } + + name += strconv.Itoa(inc) + inc++ + } + + nodeA = b.Node + nodeB = b.Iface.QFuncMain.Node + nodeB.QFuncInstance.Output[name] = portType + } + + outputPort := nodeB.CreatePort("output", name, portType) + + var inputPort *Port + if portType == types.Function { + inputPort = nodeA.CreatePort("input", name, Ports.Trigger(outputPort.QCallAll)) + } else { + inputPort = nodeA.CreatePort("input", name, portType) + } + + if reff != nil { + reff.Node = nodeB + reff.Port = inputPort + } + + if b.Type == "bp-fn-input" { + outputPort.Name_ = &RefPortName{Name: name} // When renaming port, this also need to be changed + b.Iface.Emit("_add.{name}", outputPort) + + inputPort.On("value", func(ev PortValueEvent) { + outputPort.Iface.Node.Output[outputPort.Name].Set(ev.Cable.Output.Value) + }) + + return outputPort + } + + inputPort.Name_ = &RefPortName{Name: name} // When renaming port, this also need to be changed + b.Iface.Emit("_add.{name}", inputPort) + return inputPort +} + +func (b *QBpFnInOut) renamePort(fromName string, toName string) { + bpFunction := b.Iface.QFuncMain.Node.QFuncInstance + // Main (input) -> Input (output) + if b.Type == "bp-fn-input" { + bpFunction.RenamePort("input", fromName, toName) + } else { // Output (input) -> Main (output) + bpFunction.RenamePort("output", fromName, toName) + } +} + +func (b *QBpFnInOut) deletePort(name string) { + funcMainNode := b.Iface.QFuncMain.Node + if b.Type == "bp-fn-input" { // Main (input) -> Input (output) + funcMainNode.DeletePort("input", name) + b.Node.DeletePort("output", name) + delete(funcMainNode.QFuncInstance.Input, name) + } else { // Output (input) -> Main (output) + funcMainNode.DeletePort("output", name) + b.Node.DeletePort("input", name) + delete(funcMainNode.QFuncInstance.Output, name) + } +} + +func init() { + QNodeList["BP/Fn/Input"] = &QNodeRegister{ + Metadata: &NodeMetadata{ + Output: NodePortTemplate{}, + }, + Constructor: func(i *Instance) *Node { + node := &Node{ + Instance: i, + Embed: &QNodeInput{}, + } + + iface := node.SetInterface("BPIC/BP/Fn/Input") + iface.QEnum = nodes.BPFnInput + iface.QDynamicPort = true // Port is initialized dynamically + + iface.Title = "Input" + iface.Embed.(*QBpFnInOut).Type = "bp-fn-input" + iface.QFuncMain = i.QFuncMain + i.QFuncMain.QProxyInput = node + + return node + }, + } + + QInterfaceList["BPIC/BP/Fn/Input"] = func(node *Node) *Interface { + return &Interface{ + Node: node, + Embed: &QBpFnInOut{}, + } + } + + QNodeList["BP/Fn/Output"] = &QNodeRegister{ + Metadata: &NodeMetadata{ + Input: NodePortTemplate{}, + }, + Constructor: func(i *Instance) *Node { + node := &Node{ + Instance: i, + Embed: &bpVarGet{}, + } + + iface := node.SetInterface("BPIC/BP/Fn/Output") + iface.QEnum = nodes.BPFnOutput + iface.QDynamicPort = true // Port is initialized dynamically + + iface.Title = "Output" + iface.Embed.(*QBpFnInOut).Type = "bp-fn-output" + iface.QFuncMain = i.QFuncMain + i.QFuncMain.QProxyOutput = node + + return node + }, + } + + QInterfaceList["BPIC/BP/Fn/Output"] = func(node *Node) *Interface { + return &Interface{ + Node: node, + Embed: &QBpFnInOut{}, + } + } + + QInterfaceList["BPIC/BP/Fn/Main"] = func(node *Node) *Interface { + return &Interface{ + Node: node, + Embed: &FnMain{}, + } + } +} diff --git a/blackprint/nodesBPVariable.go b/engine/nodesBPVariable.go similarity index 64% rename from blackprint/nodesBPVariable.go rename to engine/nodesBPVariable.go index 6ccedd9..525830b 100644 --- a/blackprint/nodesBPVariable.go +++ b/engine/nodesBPVariable.go @@ -1,30 +1,34 @@ -package blackprint +package engine import ( "strconv" - "github.com/blackprint/engine-go/engine" "github.com/blackprint/engine-go/engine/nodes" "github.com/blackprint/engine-go/types" "github.com/blackprint/engine-go/utils" ) type bpVarSet struct { - *engine.EmbedNode + *EmbedNode } type bpVarGet struct { - *engine.EmbedNode + *EmbedNode } -func (b *bpVarSet) Update(c *engine.Cable) { +func (b *bpVarSet) Update(c *Cable) { b.Iface.QBpVarRef.Value.Set(b.Node.Input["Val"].Get()) } type bpVarGetSet struct { - *engine.EmbedInterface + *EmbedInterface + bpVarGetSetIFace Type string - QBpVarRef *engine.BPVariable - QOnChanged func(*engine.Port) + QBpVarRef *BPVariable + QOnChanged func(*Port) +} + +type bpVarGetSetIFace interface { + QReinitPort() *Port } func (b *bpVarGetSet) Imported(data map[string]any) { @@ -37,43 +41,44 @@ func (b *bpVarGetSet) Imported(data map[string]any) { } b.ChangeVar(data["name"].(string), data["scope"].(int)) - b.QBpVarRef.Used = append(b.QBpVarRef.Used, b) + b.QBpVarRef.Used = append(b.QBpVarRef.Used, b.Iface) } -func (b *bpVarGetSet) ChangeVar(name string, scopeId int) map[string]*engine.BPVariable { +func (b *bpVarGetSet) ChangeVar(name string, scopeId int) map[string]*BPVariable { if _, exist := b.Iface.Data["name"]; exist { panic("Can't change variable node that already be initialized") } - b.Iface.Data["name"] = &engine.GetterSetter{Value: name} - b.Iface.Data["scope"] = &engine.GetterSetter{Value: scopeId} + b.Iface.Data["name"] = &GetterSetter{Value: name} + b.Iface.Data["scope"] = &GetterSetter{Value: scopeId} thisInstance := b.Node.Instance funcInstance := thisInstance.QFuncMain - if funcInstance == nil { - funcInstance.Node.QFuncInstance + var bpFunc *BPFunction + if funcInstance != nil { + bpFunc = funcInstance.Node.QFuncInstance } - var scope map[string]*engine.BPVariable - if scopeId == engine.VarScopePublic { + var scope map[string]*BPVariable + if scopeId == VarScopePublic { if funcInstance != nil { - scope := funcInstance.Node.RootInstance.Variables + scope = bpFunc.RootInstance.Variables } else { - scope := thisInstance.Variables + scope = thisInstance.Variables } - } else if scopeId == engine.VarScopeShared { - scope := funcInstance.Variables + } else if scopeId == VarScopeShared { + scope = bpFunc.Variables } else { // private - scope := thisInstance.Variables + scope = thisInstance.Variables } if _, exist := scope[name]; !exist { var scopeName string - if scopeId == engine.VarScopePublic { + if scopeId == VarScopePublic { scopeName = "public" - } else if scopeId == engine.VarScopePrivate { + } else if scopeId == VarScopePrivate { scopeName = "private" - } else if scopeId == engine.VarScopeShared { + } else if scopeId == VarScopeShared { scopeName = "shared" } else { scopeName = "unknown" @@ -85,7 +90,7 @@ func (b *bpVarGetSet) ChangeVar(name string, scopeId int) map[string]*engine.BPV return scope } -func (b *bpVarGetSet) UseType(port *engine.Port) bool { +func (b *bpVarGetSet) UseType(port *Port) bool { if b.QBpVarRef.Type != 0 { // Type was set if port == nil { b.QBpVarRef.Type = 0 // Type not set @@ -100,13 +105,13 @@ func (b *bpVarGetSet) UseType(port *engine.Port) bool { return false } -func (b *bpVarGetSet) UseType_(port *engine.Port, targetPort *engine.Port) { +func (b *bpVarGetSet) UseType_(port *Port, targetPort *Port) { b.QBpVarRef.Type = port.Type targetPort.ConnectPort(port) // Also create port for other node that using $this variable for _, item := range b.QBpVarRef.Used { - item.QReinitPort() + item.Embed.(bpVarGetSetIFace).QReinitPort() } } @@ -131,7 +136,7 @@ type iVarSet struct { QEventListen string } -func (b *iVarSet) UseType(port *engine.Port) { +func (b *iVarSet) UseType(port *Port) { if !b.bpVarGetSet.UseType(port) { b.bpVarGetSet.UseType_(port, b.QReinitPort()) } @@ -158,7 +163,7 @@ func (b *iVarSet) ChangeVar(name string, scopeId int) { b.QReinitPort() } -func (b *iVarSet) QReinitPort() *engine.Port { +func (b *iVarSet) QReinitPort() *Port { temp := b.QBpVarRef node := b.Node @@ -171,12 +176,12 @@ func (b *iVarSet) QReinitPort() *engine.Port { if temp.Type == types.Function { b.QEventListen = "call" - b.QOnChanged = func(p *engine.Port) { + b.QOnChanged = func(p *Port) { ref["Val"].Call() } } else { b.QEventListen = "value" - b.QOnChanged = func(p *engine.Port) { + b.QOnChanged = func(p *Port) { ref["Val"].Set(temp.Value.Get()) } } @@ -197,7 +202,7 @@ type iVarGet struct { *bpVarGetSet } -func (b *iVarGet) UseType(port *engine.Port) { +func (b *iVarGet) UseType(port *Port) { if !b.bpVarGetSet.UseType(port) { b.bpVarGetSet.UseType_(port, b.QReinitPort()) } @@ -216,7 +221,7 @@ func (b *iVarGet) ChangeVar(name string, scopeId int) { b.QReinitPort() } -func (b *iVarGet) QReinitPort() *engine.Port { +func (b *iVarGet) QReinitPort() *Port { input := b.Iface.Input node := b.Node temp := b.QBpVarRef @@ -226,7 +231,7 @@ func (b *iVarGet) QReinitPort() *engine.Port { } if temp.Type == types.Function { - node.CreatePort("Input", "Val", engine.Ports.Trigger(func(p *engine.Port) { + node.CreatePort("Input", "Val", Ports.Trigger(func(p *Port) { temp.Emit("call", nil) })) } else { @@ -237,11 +242,12 @@ func (b *iVarGet) QReinitPort() *engine.Port { } func init() { - RegisterNode("BP/Var/Set", &engine.NodeMetadata{ - Input: engine.NodePortTemplate{}, - }, - func(i *engine.Instance) *engine.Node { - node := &engine.Node{ + QNodeList["BP/Var/Set"] = &QNodeRegister{ + Metadata: &NodeMetadata{ + Input: NodePortTemplate{}, + }, + Constructor: func(i *Instance) *Node { + node := &Node{ Instance: i, Embed: &bpVarSet{}, } @@ -249,9 +255,9 @@ func init() { iface := node.SetInterface("BPIC/BP/Var/Set") // Specify data field from here to make it enumerable and exportable - iface.Data = engine.InterfaceData{ - "name": &engine.GetterSetter{Value: ""}, - "scope": &engine.GetterSetter{Value: engine.VarScopePublic}, + iface.Data = InterfaceData{ + "name": &GetterSetter{Value: ""}, + "scope": &GetterSetter{Value: VarScopePublic}, } iface.Title = "VarSet" @@ -260,23 +266,24 @@ func init() { iface.QDynamicPort = true return node - }) - - RegisterInterface("BPIC/BP/Var/Get", - func(node *engine.Node) *engine.Interface { - return &engine.Interface{ - Node: node, - Embed: &iVarGet{ - bpVarGetSet: &bpVarGetSet{}, - }, - } - }) + }, + } + + QInterfaceList["BPIC/BP/Var/Get"] = func(node *Node) *Interface { + return &Interface{ + Node: node, + Embed: &iVarGet{ + bpVarGetSet: &bpVarGetSet{}, + }, + } + } - RegisterNode("BP/Var/Get", &engine.NodeMetadata{ - Output: engine.NodePortTemplate{}, - }, - func(i *engine.Instance) *engine.Node { - node := &engine.Node{ + QNodeList["BP/Var/Get"] = &QNodeRegister{ + Metadata: &NodeMetadata{ + Output: NodePortTemplate{}, + }, + Constructor: func(i *Instance) *Node { + node := &Node{ Instance: i, Embed: &bpVarGet{}, } @@ -284,9 +291,9 @@ func init() { iface := node.SetInterface("BPIC/BP/Var/Get") // Specify data field from here to make it enumerable and exportable - iface.Data = engine.InterfaceData{ - "name": &engine.GetterSetter{Value: ""}, - "scope": &engine.GetterSetter{Value: engine.VarScopePublic}, + iface.Data = InterfaceData{ + "name": &GetterSetter{Value: ""}, + "scope": &GetterSetter{Value: VarScopePublic}, } iface.Title = "VarGet" @@ -295,15 +302,15 @@ func init() { iface.QDynamicPort = true return node - }) - - RegisterInterface("BPIC/BP/Var/Get", - func(node *engine.Node) *engine.Interface { - return &engine.Interface{ - Node: node, - Embed: &iVarGet{ - bpVarGetSet: &bpVarGetSet{}, - }, - } - }) + }, + } + + QInterfaceList["BPIC/BP/Var/Get"] = func(node *Node) *Interface { + return &Interface{ + Node: node, + Embed: &iVarGet{ + bpVarGetSet: &bpVarGetSet{}, + }, + } + } } diff --git a/blackprint/nodesEnvironment.go b/engine/nodesEnvironment.go similarity index 52% rename from blackprint/nodesEnvironment.go rename to engine/nodesEnvironment.go index 1241399..5ec87e6 100644 --- a/blackprint/nodesEnvironment.go +++ b/engine/nodesEnvironment.go @@ -1,25 +1,24 @@ -package blackprint +package engine import ( - "github.com/blackprint/engine-go/engine" "github.com/blackprint/engine-go/engine/nodes" "github.com/blackprint/engine-go/types" ) type bpEnvGet struct { - *engine.EmbedNode + *EmbedNode } type bpEnvSet struct { - *engine.EmbedNode + *EmbedNode } -func (b *bpEnvSet) Update(c *engine.Cable) { - Environment.Set(b.Iface.Data["name"].Get().(string), c.GetValue().(string)) +func (b *bpEnvSet) Update(c *Cable) { + QEnvironment.Set(b.Iface.Data["name"].Get().(string), c.GetValue().(string)) } type bpEnvGetSet struct { - *engine.EmbedInterface + *EmbedInterface Type string } @@ -31,8 +30,8 @@ func (b *bpEnvGetSet) Imported(data map[string]any) { b.Iface.Data["name"].Set(data["name"]) name := data["name"].(string) - if _, exists := Environment.Map[name]; !exists { - Environment.Set(name, "") + if _, exists := QEnvironment.Map[name]; !exists { + QEnvironment.Set(name, "") } } @@ -45,7 +44,7 @@ func (b *iEnvGet) Imported(data map[string]any) { b.bpEnvGetSet.Imported(data) b.QListener = func(v any) { - ev := v.(*engine.EnvironmentEvent) + ev := v.(*EnvironmentEvent) if ev.Key != b.Iface.Data["name"].Get().(string) { return } @@ -54,7 +53,7 @@ func (b *iEnvGet) Imported(data map[string]any) { } Event.On("environment.changed environment.added", b.QListener) - b.Ref.Output["Val"].Set(Environment.Map[b.Iface.Data["name"].Get().(string)]) + b.Ref.Output["Val"].Set(QEnvironment.Map[b.Iface.Data["name"].Get().(string)]) } func (b *iEnvGet) Destroy() { @@ -70,13 +69,14 @@ type iEnvSet struct { } func init() { - RegisterNode("BP/Env/Get", &engine.NodeMetadata{ - Output: engine.NodePortTemplate{ - "Val": types.String, + QNodeList["BP/Env/Get"] = &QNodeRegister{ + Metadata: &NodeMetadata{ + Output: NodePortTemplate{ + "Val": types.String, + }, }, - }, - func(i *engine.Instance) *engine.Node { - node := &engine.Node{ + Constructor: func(i *Instance) *Node { + node := &Node{ Instance: i, Embed: &bpEnvGet{}, } @@ -84,8 +84,8 @@ func init() { iface := node.SetInterface("BPIC/BP/Env/Get") // Specify data field from here to make it enumerable and exportable - iface.Data = engine.InterfaceData{ - "name": &engine.GetterSetter{Value: ""}, + iface.Data = InterfaceData{ + "name": &GetterSetter{Value: ""}, } iface.Title = "EnvGet" @@ -93,25 +93,25 @@ func init() { iface.QEnum = nodes.BPEnvGet return node - }) - - RegisterInterface("BPIC/BP/Env/Get", - func(node *engine.Node) *engine.Interface { - return &engine.Interface{ - Node: node, - Embed: &iEnvGet{ - bpEnvGetSet: &bpEnvGetSet{}, - }, - } - }) + }, + } + + QInterfaceList["BPIC/BP/Env/Get"] = func(node *Node) *Interface { + return &Interface{ + Embed: &iEnvGet{ + bpEnvGetSet: &bpEnvGetSet{}, + }, + } + } - RegisterNode("BP/Env/Set", &engine.NodeMetadata{ - Input: engine.NodePortTemplate{ - "Val": types.String, + QNodeList["BP/Env/Set"] = &QNodeRegister{ + Metadata: &NodeMetadata{ + Input: NodePortTemplate{ + "Val": types.String, + }, }, - }, - func(i *engine.Instance) *engine.Node { - node := &engine.Node{ + Constructor: func(i *Instance) *Node { + node := &Node{ Instance: i, Embed: &bpEnvSet{}, } @@ -119,8 +119,8 @@ func init() { iface := node.SetInterface("BPIC/BP/Env/Set") // Specify data field from here to make it enumerable and exportable - iface.Data = engine.InterfaceData{ - "name": &engine.GetterSetter{Value: ""}, + iface.Data = InterfaceData{ + "name": &GetterSetter{Value: ""}, } iface.Title = "EnvSet" @@ -128,15 +128,14 @@ func init() { iface.QEnum = nodes.BPEnvSet return node - }) - - RegisterInterface("BPIC/BP/Env/Set", - func(node *engine.Node) *engine.Interface { - return &engine.Interface{ - Node: node, - Embed: &iEnvSet{ - bpEnvGetSet: &bpEnvGetSet{}, - }, - } - }) + }, + } + + QInterfaceList["BPIC/BP/Env/Set"] = func(node *Node) *Interface { + return &Interface{ + Embed: &iEnvSet{ + bpEnvGetSet: &bpEnvGetSet{}, + }, + } + } } diff --git a/blackprint/nodesFnPortVar.go b/engine/nodesFnPortVar.go similarity index 72% rename from blackprint/nodesFnPortVar.go rename to engine/nodesFnPortVar.go index aca2e53..9b3acb4 100644 --- a/blackprint/nodesFnPortVar.go +++ b/engine/nodesFnPortVar.go @@ -1,13 +1,12 @@ -package blackprint +package engine import ( - "github.com/blackprint/engine-go/engine" "github.com/blackprint/engine-go/engine/nodes" "github.com/blackprint/engine-go/types" ) type fnVarInput struct { - *engine.EmbedNode + *EmbedNode } func (f *fnVarInput) Imported(data map[string]any) { @@ -16,7 +15,7 @@ func (f *fnVarInput) Imported(data map[string]any) { } } -func (f *fnVarInput) Request(cable *engine.Cable) { +func (f *fnVarInput) Request(cable *Cable) { iface := f.Iface // This will trigger the port to request from outside and assign to this node's port @@ -24,22 +23,22 @@ func (f *fnVarInput) Request(cable *engine.Cable) { } type fnVarOutput struct { - *engine.EmbedNode + *EmbedNode } -func (f *fnVarOutput) Update(c *engine.Cable) { - id := f.Iface.Data["name"].Get() - f.RefOutput[id].Set(f.Ref.Input["Val"].Get()) +func (f *fnVarOutput) Update(c *Cable) { + id := f.Iface.Data["name"].Get().(string) + f.Node.RefOutput[id].Set(f.Ref.Input["Val"].Get()) } type bpFnVarInOut struct { - *engine.EmbedInterface - QOnConnect func(*engine.Cable, *engine.Port) + *EmbedInterface + QOnConnect func(*Cable, *Port) - QParentFunc *engine.Interface - QProxyIface *engine.Interface + QParentFunc *Interface + QProxyIface *Interface QListener func(any) - QWaitPortInit func(*engine.Port) + QWaitPortInit func(*Port) Type string } @@ -70,7 +69,7 @@ func (f *fnVarInputIface) Imported(data map[string]any) { proxyIface := f.QProxyIface // Run when $this node is being connected with other node - iPort.QOnConnect = func(cable *engine.Cable, port *engine.Port) bool { + iPort.QOnConnect = func(cable *Cable, port *Port) bool { iPort.QOnConnect = nil proxyIface.Off("_add."+name, iPort.QWaitPortInit) iPort.QWaitPortInit = nil @@ -78,24 +77,24 @@ func (f *fnVarInputIface) Imported(data map[string]any) { cable.Disconnect() node.DeletePort("output", "Val") - portName := &engine.RefPortName{Name: name} + portName := &RefPortName{Name: name} portType := getFnPortType(port, "input", f.QParentFunc, portName) newPort := node.CreatePort("output", "Val", portType) newPort.Name_ = portName newPort.ConnectPort(port) - proxyIface.Embed.(*bpFnInOut).AddPort(port, name) + proxyIface.Embed.(*QBpFnInOut).AddPort(port, name) f.QAddListener() return true } // Run when main node is the missing port - iPort.QWaitPortInit = func(port *engine.Port) { + iPort.QWaitPortInit = func(port *Port) { iPort.QOnConnect = nil iPort.QWaitPortInit = nil - backup := []*engine.Port{} + backup := []*Port{} for _, val := range f.Iface.Output["Val"].Cables { backup = append(backup, val.Input) } @@ -127,7 +126,7 @@ func (f *fnVarInputIface) Imported(data map[string]any) { func (f *fnVarInputIface) QAddListener() { port := f.QProxyIface.Output[f.Iface.Data["name"].Get().(string)] - if port.Feature == engine.PortTypeTrigger { + if port.Feature == PortTypeTrigger { f.QListener = func(p any) { f.Ref.Output["Val"].Call() } @@ -135,7 +134,7 @@ func (f *fnVarInputIface) QAddListener() { port.On("call", f.QListener) } else { f.QListener = func(ev any) { - port := ev.(*engine.PortSelfEvent).Port + port := ev.(*PortValueEvent).Port if port.Iface.Node.Routes.Out == nil { val := f.Ref.IOutput["Val"] val.Value = port.Value // Change value without trigger node.update @@ -162,7 +161,7 @@ func (f *fnVarInputIface) Destroy() { } port := f.QProxyIface.Output[f.Iface.Data["name"].Get().(string)] - if port.Feature == engine.PortTypeTrigger { + if port.Feature == PortTypeTrigger { port.Off("call", f.QListener) } else { port.Off("value", f.QListener) @@ -187,7 +186,7 @@ func (f *fnVarOutputIface) Imported(data map[string]any) { proxyIface := f.QParentFunc.QProxyOutput.Iface // Run when $this node is being connected with other node - iPort.QOnConnect = func(cable *engine.Cable, port *engine.Port) bool { + iPort.QOnConnect = func(cable *Cable, port *Port) bool { iPort.QOnConnect = nil proxyIface.Off("_add."+name, iPort.QWaitPortInit) iPort.QWaitPortInit = nil @@ -195,22 +194,22 @@ func (f *fnVarOutputIface) Imported(data map[string]any) { cable.Disconnect() node.DeletePort("input", "Val") - portName := &engine.RefPortName{Name: name} + portName := &RefPortName{Name: name} portType := getFnPortType(port, "output", f.QParentFunc, portName) newPort := node.CreatePort("input", "Val", portType) newPort.Name_ = portName newPort.ConnectPort(port) - proxyIface.Embed.(*bpFnInOut).AddPort(port, name) + proxyIface.Embed.(*QBpFnInOut).AddPort(port, name) return true } // Run when main node is the missing port - iPort.QWaitPortInit = func(port *engine.Port) { + iPort.QWaitPortInit = func(port *Port) { iPort.QOnConnect = nil iPort.QWaitPortInit = nil - backup := []*engine.Port{} + backup := []*Port{} for _, val := range f.Iface.Output["Val"].Cables { backup = append(backup, val.Input) } @@ -236,12 +235,12 @@ func (f *fnVarOutputIface) Imported(data map[string]any) { } } -func getFnPortType(port *engine.Port, which string, parentNode *engine.BPFunctionNode, ref *engine.RefPortName) any { - if port.Feature == engine.PortTypeTrigger { +func getFnPortType(port *Port, which string, parentNode *Interface, ref *RefPortName) any { + if port.Feature == PortTypeTrigger { if which == "input" { // Function Input (has output port inside, and input port on main node) return types.Function } else { - return engine.Ports.Trigger(parentNode.Iface.Output[ref.Name].CallAll) + return Ports.Trigger(parentNode.Output[ref.Name].QCallAll) } } else { if port.Feature != 0 { @@ -253,11 +252,12 @@ func getFnPortType(port *engine.Port, which string, parentNode *engine.BPFunctio } func init() { - RegisterNode("BP/FnVar/Input", &engine.NodeMetadata{ - Output: engine.NodePortTemplate{}, - }, - func(i *engine.Instance) *engine.Node { - node := &engine.Node{ + QNodeList["BP/FnVar/Input"] = &QNodeRegister{ + Metadata: &NodeMetadata{ + Output: NodePortTemplate{}, + }, + Constructor: func(i *Instance) *Node { + node := &Node{ Instance: i, Embed: &fnVarInput{}, } @@ -265,8 +265,8 @@ func init() { iface := node.SetInterface("BPIC/BP/FnVar/Input") // Specify data field from here to make it enumerable and exportable - iface.Data = engine.InterfaceData{ - "name": &engine.GetterSetter{Value: ""}, + iface.Data = InterfaceData{ + "name": &GetterSetter{Value: ""}, } iface.Title = "FnInput" @@ -275,23 +275,23 @@ func init() { iface.QDynamicPort = true return node - }) - - RegisterInterface("BPIC/BP/FnVar/Input", - func(node *engine.Node) *engine.Interface { - return &engine.Interface{ - Node: node, - Embed: &fnVarInputIface{ - bpFnVarInOut: &bpFnVarInOut{}, - }, - } - }) + }, + } + + QInterfaceList["BPIC/BP/FnVar/Input"] = func(node *Node) *Interface { + return &Interface{ + Embed: &fnVarInputIface{ + bpFnVarInOut: &bpFnVarInOut{}, + }, + } + } - RegisterNode("BP/FnVar/Output", &engine.NodeMetadata{ - Input: engine.NodePortTemplate{}, - }, - func(i *engine.Instance) *engine.Node { - node := &engine.Node{ + QNodeList["BP/FnVar/Output"] = &QNodeRegister{ + Metadata: &NodeMetadata{ + Input: NodePortTemplate{}, + }, + Constructor: func(i *Instance) *Node { + node := &Node{ Instance: i, Embed: &fnVarOutput{}, } @@ -299,8 +299,8 @@ func init() { iface := node.SetInterface("BPIC/BP/FnVar/Output") // Specify data field from here to make it enumerable and exportable - iface.Data = engine.InterfaceData{ - "name": &engine.GetterSetter{Value: ""}, + iface.Data = InterfaceData{ + "name": &GetterSetter{Value: ""}, } iface.Title = "FnOutput" @@ -309,15 +309,14 @@ func init() { iface.QDynamicPort = true return node - }) - - RegisterInterface("BPIC/BP/FnVar/Output", - func(node *engine.Node) *engine.Interface { - return &engine.Interface{ - Node: node, - Embed: &fnVarOutputIface{ - bpFnVarInOut: &bpFnVarInOut{}, - }, - } - }) + }, + } + + QInterfaceList["BPIC/BP/FnVar/Output"] = func(node *Node) *Interface { + return &Interface{ + Embed: &fnVarOutputIface{ + bpFnVarInOut: &bpFnVarInOut{}, + }, + } + } } diff --git a/engine/port.go b/engine/port.go index a447df2..52504a4 100644 --- a/engine/port.go +++ b/engine/port.go @@ -42,7 +42,7 @@ type Port struct { QStructSplitted bool QGhost bool QFunc func(*Port) - QCallAll func() + QCallAll func(*Port) QOnConnect func(*Cable, *Port) bool QWaitPortInit func(*Port) } @@ -168,11 +168,11 @@ func (port *Port) QCableConnectError(name string, obj *CableErrorEvent, severe b } if obj.Port != nil { - msg += fmt.Sprintf("\nFrom port: %s (iface: %s)\n - Type: %s) (%s)", obj.Port.Name, obj.Port.Iface.Namespace, obj.Port.Source, obj.Port.Type) + msg += fmt.Sprintf("\nFrom port: %s (iface: %s)\n - Type: %d) (%d)", obj.Port.Name, obj.Port.Iface.Namespace, obj.Port.Source, obj.Port.Type) } if obj.Target != nil { - msg += fmt.Sprintf("\nTo port: %s (iface: %s)\n - Type: %s) (%s)", obj.Target.Name, obj.Target.Iface.Namespace, obj.Target.Source, obj.Target.Type) + msg += fmt.Sprintf("\nTo port: %s (iface: %s)\n - Type: %d) (%d)", obj.Target.Name, obj.Target.Iface.Namespace, obj.Target.Source, obj.Target.Type) } obj.Message = msg diff --git a/engine/portFeature.go b/engine/portFeature.go index f406e4a..d63bb27 100644 --- a/engine/portFeature.go +++ b/engine/portFeature.go @@ -68,7 +68,7 @@ func portStructOf_unsplit(port *Port) { parent.Splitted = false node := port.Iface.Node - for key, _ := range parent.Struct { + for key := range parent.Struct { node.DeletePort("output", parent.Name+key) } } @@ -85,7 +85,7 @@ func portStructOf_handle(port *Port, data any) { } } } else { - for key, _ := range port.Struct { + for key := range port.Struct { output[key].Set(nil) } } diff --git a/engine/routePort.go b/engine/routePort.go index e322823..cb9bb15 100644 --- a/engine/routePort.go +++ b/engine/routePort.go @@ -82,8 +82,8 @@ func (r *RoutePort) RouteOut() { if r.Out == nil { if r.Iface.QEnum == nodes.BPFnOutput { node := r.Iface.QFuncMain.Node - route := node.Routes.(*RoutePort) - route.RouteIn() + route := node.Routes + route.RouteIn(nil) } return @@ -103,7 +103,7 @@ func (r *RoutePort) RouteOut() { routes.RouteIn(r.Out) } else if enum == nodes.BPFnOutput { node := targetRoute.Iface.QFuncMain.Node - routes := node.Routes.(*RoutePort) + routes := node.Routes routes.RouteIn(r.Out) } else { targetRoute.RouteIn(r.Out) diff --git a/example/input.go b/example/input.go index d9e0ea6..5b5b2f4 100644 --- a/example/input.go +++ b/example/input.go @@ -43,17 +43,17 @@ func (this *InputSimpleIFace) Changed(val any) { } type MyData struct { - Iface any - val any + engine.GetterSetter + Value any } func (gs *MyData) Set(val any) { - gs.val = val - gs.Iface.(*InputSimpleIFace).Changed(gs.val) + gs.Value = val + gs.Iface.Embed.(*InputSimpleIFace).Changed(gs.Value) } func (gs *MyData) Get() any { - return gs.val + return gs.Value } // This will be called from example.go @@ -80,7 +80,7 @@ func init() { func(node *engine.Node) *engine.Interface { iface := &engine.Interface{ Data: engine.InterfaceData{ - "value": &MyData{val: "..."}, + "value": &MyData{Value: "..."}, }, Embed: &InputSimpleIFace{}, } From e02c5b3482f03133eec72756872fe891cdb71f90 Mon Sep 17 00:00:00 2001 From: StefansArya Date: Fri, 9 Sep 2022 22:43:16 +0700 Subject: [PATCH 12/15] Simplify design and implementation --- blackprint/blackprint.go | 11 +++---- engine/engine.go | 12 +++---- engine/interface.go | 2 +- engine/node.go | 29 +++++++++-------- engine/nodesBPFunction.go | 65 ++++++++++++++------------------------ engine/nodesBPVariable.go | 52 +++++++++++------------------- engine/nodesEnvironment.go | 54 ++++++++++++------------------- engine/nodesFnPortVar.go | 50 +++++++++++------------------ example/button.go | 28 +++++++--------- example/input.go | 33 ++++++++----------- example/logger.go | 25 +++++++-------- example/math.go | 33 +++++++------------ 12 files changed, 152 insertions(+), 242 deletions(-) diff --git a/blackprint/blackprint.go b/blackprint/blackprint.go index bc15e77..83d4f9f 100644 --- a/blackprint/blackprint.go +++ b/blackprint/blackprint.go @@ -7,20 +7,17 @@ import ( ) // The constructor must return pointer (ex: &Node{}) -func RegisterNode(namespace string, meta *engine.NodeMetadata, constructor engine.NodeConstructor) { - engine.QNodeList[namespace] = &engine.QNodeRegister{ - Metadata: meta, - Constructor: constructor, - } +func RegisterNode(namespace string, meta *engine.NodeRegister) { + engine.QNodeList[namespace] = meta } // The constructor must return pointer (ex: &any) -func RegisterInterface(namespace string, constructor engine.InterfaceConstructor) { +func RegisterInterface(namespace string, meta *engine.InterfaceRegister) { if strings.HasPrefix(namespace, "BPIC/") == false { panic(namespace + ": The first parameter of 'RegisterInterface' must be started with BPIC to avoid name conflict. Please name the interface similar with 'templatePrefix' for your module that you have set on 'blackprint.config.js'.") } - engine.QInterfaceList[namespace] = constructor + engine.QInterfaceList[namespace] = meta } var Event = engine.Event diff --git a/engine/engine.go b/engine/engine.go index f11a911..026820a 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -104,11 +104,6 @@ type ImportOptions struct { AppendMode bool } -type QNodeRegister struct { - Metadata *NodeMetadata - Constructor NodeConstructor -} - func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inserted []*Interface, err error) { var data SingleInstanceJSON @@ -384,7 +379,8 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes panic("Node nodes for " + namespace + " was not found, maybe .registerNode() haven't being called?") } } else { - node = func_.Constructor(instance) // func_ from registerNode(namespace, func_) + node = &Node{Instance: instance} + func_.Constructor(node) } // Disable data flow on any node ports @@ -407,7 +403,7 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes // Create the linker between the nodes and the iface if isFuncNode == false { - iface.QPrepare(func_.Metadata) + iface.QPrepare(func_) } if options.Id != "" { @@ -524,7 +520,7 @@ func (instance *Instance) CreateFunction(id string, options any) *BPFunction { Output: NodePortTemplate{}, } - meta := &NodeMetadata{ + meta := &NodeRegister{ Input: temp.Input, Output: temp.Output, } diff --git a/engine/interface.go b/engine/interface.go index 12889bc..2756315 100644 --- a/engine/interface.go +++ b/engine/interface.go @@ -77,7 +77,7 @@ func (iface *Interface) QBpFnInit() {} var reflectKind = reflect.TypeOf(reflect.Int) // Private (to be called for internal library only) -func (iface *Interface) QPrepare(meta *NodeMetadata) { +func (iface *Interface) QPrepare(meta *NodeRegister) { iface.CustomEvent = &CustomEvent{} ref := &referencesShortcut{} diff --git a/engine/node.go b/engine/node.go index b93735c..e3d273b 100644 --- a/engine/node.go +++ b/engine/node.go @@ -55,28 +55,33 @@ func (n *Node) Imported(d map[string]any) { n.Embed.Imported(d) } func (n *Node) Destroy() { n.Embed.Destroy() } func (n *Node) SyncIn(id string, data ...any) { n.Embed.SyncIn(id, data) } -type NodeMetadata struct { +type NodeRegister struct { // Port Template Output NodePortTemplate Input NodePortTemplate // Property *NodePortTemplate + + Constructor NodeConstructor +} + +type InterfaceRegister struct { + Constructor InterfaceConstructor } -type NodeConstructor func(*Instance) *Node -type InterfaceConstructor func(*Node) *Interface +type NodeConstructor func(*Node) +type InterfaceConstructor func(*Interface) // QNodeList = Private function, for internal library only -var QNodeList = map[string]*QNodeRegister{} +var QNodeList = map[string]*NodeRegister{} // QInterfaceList = Private function, for internal library only -var QInterfaceList = map[string]InterfaceConstructor{} +var QInterfaceList = map[string]*InterfaceRegister{} -// This will return *pointer func (n *Node) SetInterface(namespace ...string) *Interface { - if len(namespace) == 0 { - // Default interface (BP/Default) - iface := &Interface{QInitialized: true, Importing: true} + iface := &Interface{QInitialized: true, Importing: true} + // Default interface (BP/Default) + if len(namespace) == 0 { n.Iface = iface return iface } @@ -87,11 +92,7 @@ func (n *Node) SetInterface(namespace ...string) *Interface { panic("Node interface for '" + name + "' was not found, maybe .registerInterface() haven't being called?") } - iface := class(n) - if utils.IsPointer(iface) == false { - panic(".registerInterface() must return pointer") - } - + class.Constructor(iface) for _, val := range iface.Data { utils.SetProperty(val, "Iface", iface) } diff --git a/engine/nodesBPFunction.go b/engine/nodesBPFunction.go index 3bf804b..367f7ab 100644 --- a/engine/nodesBPFunction.go +++ b/engine/nodesBPFunction.go @@ -538,15 +538,10 @@ func (b *QBpFnInOut) deletePort(name string) { } func init() { - QNodeList["BP/Fn/Input"] = &QNodeRegister{ - Metadata: &NodeMetadata{ - Output: NodePortTemplate{}, - }, - Constructor: func(i *Instance) *Node { - node := &Node{ - Instance: i, - Embed: &QNodeInput{}, - } + QNodeList["BP/Fn/Input"] = &NodeRegister{ + Output: NodePortTemplate{}, + Constructor: func(node *Node) { + node.Embed = &QNodeInput{} iface := node.SetInterface("BPIC/BP/Fn/Input") iface.QEnum = nodes.BPFnInput @@ -554,29 +549,21 @@ func init() { iface.Title = "Input" iface.Embed.(*QBpFnInOut).Type = "bp-fn-input" - iface.QFuncMain = i.QFuncMain - i.QFuncMain.QProxyInput = node - - return node + iface.QFuncMain = node.Instance.QFuncMain + iface.QFuncMain.QProxyInput = node }, } - QInterfaceList["BPIC/BP/Fn/Input"] = func(node *Node) *Interface { - return &Interface{ - Node: node, - Embed: &QBpFnInOut{}, - } + QInterfaceList["BPIC/BP/Fn/Input"] = &InterfaceRegister{ + Constructor: func(iface *Interface) { + iface.Embed = &QBpFnInOut{} + }, } - QNodeList["BP/Fn/Output"] = &QNodeRegister{ - Metadata: &NodeMetadata{ - Input: NodePortTemplate{}, - }, - Constructor: func(i *Instance) *Node { - node := &Node{ - Instance: i, - Embed: &bpVarGet{}, - } + QNodeList["BP/Fn/Output"] = &NodeRegister{ + Input: NodePortTemplate{}, + Constructor: func(node *Node) { + node.Embed = &bpVarGet{} iface := node.SetInterface("BPIC/BP/Fn/Output") iface.QEnum = nodes.BPFnOutput @@ -584,24 +571,20 @@ func init() { iface.Title = "Output" iface.Embed.(*QBpFnInOut).Type = "bp-fn-output" - iface.QFuncMain = i.QFuncMain - i.QFuncMain.QProxyOutput = node - - return node + iface.QFuncMain = node.Instance.QFuncMain + iface.QFuncMain.QProxyOutput = node }, } - QInterfaceList["BPIC/BP/Fn/Output"] = func(node *Node) *Interface { - return &Interface{ - Node: node, - Embed: &QBpFnInOut{}, - } + QInterfaceList["BPIC/BP/Fn/Output"] = &InterfaceRegister{ + Constructor: func(iface *Interface) { + iface.Embed = &QBpFnInOut{} + }, } - QInterfaceList["BPIC/BP/Fn/Main"] = func(node *Node) *Interface { - return &Interface{ - Node: node, - Embed: &FnMain{}, - } + QInterfaceList["BPIC/BP/Fn/Main"] = &InterfaceRegister{ + Constructor: func(iface *Interface) { + iface.Embed = &FnMain{} + }, } } diff --git a/engine/nodesBPVariable.go b/engine/nodesBPVariable.go index 525830b..0ed9652 100644 --- a/engine/nodesBPVariable.go +++ b/engine/nodesBPVariable.go @@ -242,15 +242,10 @@ func (b *iVarGet) QReinitPort() *Port { } func init() { - QNodeList["BP/Var/Set"] = &QNodeRegister{ - Metadata: &NodeMetadata{ - Input: NodePortTemplate{}, - }, - Constructor: func(i *Instance) *Node { - node := &Node{ - Instance: i, - Embed: &bpVarSet{}, - } + QNodeList["BP/Var/Set"] = &NodeRegister{ + Input: NodePortTemplate{}, + Constructor: func(node *Node) { + node.Embed = &bpVarSet{} iface := node.SetInterface("BPIC/BP/Var/Set") @@ -264,29 +259,21 @@ func init() { iface.Embed.(*iVarSet).Type = "bp-var-set" iface.QEnum = nodes.BPVarSet iface.QDynamicPort = true - - return node }, } - QInterfaceList["BPIC/BP/Var/Get"] = func(node *Node) *Interface { - return &Interface{ - Node: node, - Embed: &iVarGet{ + QInterfaceList["BPIC/BP/Var/Set"] = &InterfaceRegister{ + Constructor: func(iface *Interface) { + iface.Embed = &iVarSet{ bpVarGetSet: &bpVarGetSet{}, - }, - } + } + }, } - QNodeList["BP/Var/Get"] = &QNodeRegister{ - Metadata: &NodeMetadata{ - Output: NodePortTemplate{}, - }, - Constructor: func(i *Instance) *Node { - node := &Node{ - Instance: i, - Embed: &bpVarGet{}, - } + QNodeList["BP/Var/Get"] = &NodeRegister{ + Output: NodePortTemplate{}, + Constructor: func(node *Node) { + node.Embed = &bpVarGet{} iface := node.SetInterface("BPIC/BP/Var/Get") @@ -300,17 +287,14 @@ func init() { iface.Embed.(*iVarGet).Type = "bp-var-get" iface.QEnum = nodes.BPVarGet iface.QDynamicPort = true - - return node }, } - QInterfaceList["BPIC/BP/Var/Get"] = func(node *Node) *Interface { - return &Interface{ - Node: node, - Embed: &iVarGet{ + QInterfaceList["BPIC/BP/Var/Get"] = &InterfaceRegister{ + Constructor: func(iface *Interface) { + iface.Embed = &iVarGet{ bpVarGetSet: &bpVarGetSet{}, - }, - } + } + }, } } diff --git a/engine/nodesEnvironment.go b/engine/nodesEnvironment.go index 5ec87e6..cc1220d 100644 --- a/engine/nodesEnvironment.go +++ b/engine/nodesEnvironment.go @@ -69,17 +69,12 @@ type iEnvSet struct { } func init() { - QNodeList["BP/Env/Get"] = &QNodeRegister{ - Metadata: &NodeMetadata{ - Output: NodePortTemplate{ - "Val": types.String, - }, + QNodeList["BP/Env/Get"] = &NodeRegister{ + Output: NodePortTemplate{ + "Val": types.String, }, - Constructor: func(i *Instance) *Node { - node := &Node{ - Instance: i, - Embed: &bpEnvGet{}, - } + Constructor: func(node *Node) { + node.Embed = &bpEnvGet{} iface := node.SetInterface("BPIC/BP/Env/Get") @@ -91,30 +86,23 @@ func init() { iface.Title = "EnvGet" iface.Embed.(*iEnvGet).Type = "bp-env-get" iface.QEnum = nodes.BPEnvGet - - return node }, } - QInterfaceList["BPIC/BP/Env/Get"] = func(node *Node) *Interface { - return &Interface{ - Embed: &iEnvGet{ + QInterfaceList["BPIC/BP/Env/Get"] = &InterfaceRegister{ + Constructor: func(iface *Interface) { + iface.Embed = &iEnvGet{ bpEnvGetSet: &bpEnvGetSet{}, - }, - } + } + }, } - QNodeList["BP/Env/Set"] = &QNodeRegister{ - Metadata: &NodeMetadata{ - Input: NodePortTemplate{ - "Val": types.String, - }, + QNodeList["BP/Env/Set"] = &NodeRegister{ + Input: NodePortTemplate{ + "Val": types.String, }, - Constructor: func(i *Instance) *Node { - node := &Node{ - Instance: i, - Embed: &bpEnvSet{}, - } + Constructor: func(node *Node) { + node.Embed = &bpEnvSet{} iface := node.SetInterface("BPIC/BP/Env/Set") @@ -126,16 +114,14 @@ func init() { iface.Title = "EnvSet" iface.Embed.(*iEnvSet).Type = "bp-env-set" iface.QEnum = nodes.BPEnvSet - - return node }, } - QInterfaceList["BPIC/BP/Env/Set"] = func(node *Node) *Interface { - return &Interface{ - Embed: &iEnvSet{ + QInterfaceList["BPIC/BP/Env/Set"] = &InterfaceRegister{ + Constructor: func(iface *Interface) { + iface.Embed = &iEnvSet{ bpEnvGetSet: &bpEnvGetSet{}, - }, - } + } + }, } } diff --git a/engine/nodesFnPortVar.go b/engine/nodesFnPortVar.go index 9b3acb4..717202b 100644 --- a/engine/nodesFnPortVar.go +++ b/engine/nodesFnPortVar.go @@ -252,15 +252,10 @@ func getFnPortType(port *Port, which string, parentNode *Interface, ref *RefPort } func init() { - QNodeList["BP/FnVar/Input"] = &QNodeRegister{ - Metadata: &NodeMetadata{ - Output: NodePortTemplate{}, - }, - Constructor: func(i *Instance) *Node { - node := &Node{ - Instance: i, - Embed: &fnVarInput{}, - } + QNodeList["BP/FnVar/Input"] = &NodeRegister{ + Output: NodePortTemplate{}, + Constructor: func(node *Node) { + node.Embed = &fnVarInput{} iface := node.SetInterface("BPIC/BP/FnVar/Input") @@ -273,28 +268,21 @@ func init() { iface.Embed.(*fnVarInputIface).Type = "bp-fnvar-input" iface.QEnum = nodes.BPFnVarInput iface.QDynamicPort = true - - return node }, } - QInterfaceList["BPIC/BP/FnVar/Input"] = func(node *Node) *Interface { - return &Interface{ - Embed: &fnVarInputIface{ + QInterfaceList["BPIC/BP/FnVar/Input"] = &InterfaceRegister{ + Constructor: func(iface *Interface) { + iface.Embed = &fnVarInputIface{ bpFnVarInOut: &bpFnVarInOut{}, - }, - } + } + }, } - QNodeList["BP/FnVar/Output"] = &QNodeRegister{ - Metadata: &NodeMetadata{ - Input: NodePortTemplate{}, - }, - Constructor: func(i *Instance) *Node { - node := &Node{ - Instance: i, - Embed: &fnVarOutput{}, - } + QNodeList["BP/FnVar/Output"] = &NodeRegister{ + Input: NodePortTemplate{}, + Constructor: func(node *Node) { + node.Embed = &fnVarOutput{} iface := node.SetInterface("BPIC/BP/FnVar/Output") @@ -307,16 +295,14 @@ func init() { iface.Embed.(*fnVarOutputIface).Type = "bp-fnvar-output" iface.QEnum = nodes.BPFnVarOutput iface.QDynamicPort = true - - return node }, } - QInterfaceList["BPIC/BP/FnVar/Output"] = func(node *Node) *Interface { - return &Interface{ - Embed: &fnVarOutputIface{ + QInterfaceList["BPIC/BP/FnVar/Output"] = &InterfaceRegister{ + Constructor: func(iface *Interface) { + iface.Embed = &fnVarOutputIface{ bpFnVarInOut: &bpFnVarInOut{}, - }, - } + } + }, } } diff --git a/example/button.go b/example/button.go index bb2f271..02aaa90 100644 --- a/example/button.go +++ b/example/button.go @@ -23,25 +23,21 @@ func (iface *ButtonSimpleIFace) Clicked(ev any) { // This will be called from example.go func init() { - Blackprint.RegisterNode("Example/Button/Simple", &engine.NodeMetadata{ + Blackprint.RegisterNode("Example/Button/Simple", &engine.NodeRegister{ Output: engine.NodePortTemplate{}, Input: engine.NodePortTemplate{}, - }, - func(instance *engine.Instance) *engine.Node { - node := &engine.Node{ - Embed: &ButtonSimple{}, - } + + Constructor: func(node *engine.Node) { + node.Embed = &ButtonSimple{} iface := node.SetInterface("BPIC/Example/Button") iface.Title = "Button" - - return node - }) - - Blackprint.RegisterInterface("BPIC/Example/Button", - func(node *engine.Node) *engine.Interface { - return &engine.Interface{ - Embed: &ButtonSimpleIFace{}, - } - }) + }, + }) + + Blackprint.RegisterInterface("BPIC/Example/Button", &engine.InterfaceRegister{ + Constructor: func(iface *engine.Interface) { + iface.Embed = &ButtonSimpleIFace{} + }, + }) } diff --git a/example/input.go b/example/input.go index 5b5b2f4..bcf0203 100644 --- a/example/input.go +++ b/example/input.go @@ -58,33 +58,26 @@ func (gs *MyData) Get() any { // This will be called from example.go func init() { - Blackprint.RegisterNode("Example/Input/Simple", &engine.NodeMetadata{ + Blackprint.RegisterNode("Example/Input/Simple", &engine.NodeRegister{ Output: engine.NodePortTemplate{ "Changed": types.Function, "Value": types.String, }, - }, - func(instance *engine.Instance) *engine.Node { - node := &engine.Node{ - Instance: instance, - Embed: &InputSimple{}, - } + + Constructor: func(node *engine.Node) { + node.Embed = &InputSimple{} iface := node.SetInterface("BPIC/Example/Input") iface.Title = "Input" + }, + }) - return node - }) - - Blackprint.RegisterInterface("BPIC/Example/Input", - func(node *engine.Node) *engine.Interface { - iface := &engine.Interface{ - Data: engine.InterfaceData{ - "value": &MyData{Value: "..."}, - }, - Embed: &InputSimpleIFace{}, + Blackprint.RegisterInterface("BPIC/Example/Input", &engine.InterfaceRegister{ + Constructor: func(iface *engine.Interface) { + iface.Embed = &InputSimpleIFace{} + iface.Data = engine.InterfaceData{ + "value": &MyData{Value: "..."}, } - - return iface - }) + }, + }) } diff --git a/example/logger.go b/example/logger.go index fba971a..39fd041 100644 --- a/example/logger.go +++ b/example/logger.go @@ -65,25 +65,22 @@ func (iface *LoggerIFace) Log(val ...any) any { } func init() { - Blackprint.RegisterNode("Example/Display/Logger", &engine.NodeMetadata{ + Blackprint.RegisterNode("Example/Display/Logger", &engine.NodeRegister{ Input: engine.NodePortTemplate{ "Any": engine.Ports.ArrayOf(types.Any), // nil => Any }, - }, - func(instance *engine.Instance) *engine.Node { - node := &engine.Node{ - Instance: instance, - Embed: &LoggerNode{}, - } + + Constructor: func(node *engine.Node) { + node.Embed = &LoggerNode{} iface := node.SetInterface("BPIC/Example/Display/Logger") iface.Title = "Logger" + }, + }) - return node - }) - - Blackprint.RegisterInterface("BPIC/Example/Display/Logger", - func(node *engine.Node) *engine.Interface { - return &engine.Interface{Embed: &LoggerIFace{}} - }) + Blackprint.RegisterInterface("BPIC/Example/Display/Logger", &engine.InterfaceRegister{ + Constructor: func(iface *engine.Interface) { + iface.Embed = &LoggerIFace{} + }, + }) } diff --git a/example/math.go b/example/math.go index 9727320..55665cb 100644 --- a/example/math.go +++ b/example/math.go @@ -28,7 +28,7 @@ func (this *MathMultiple) Update(cable *engine.Cable) { } func init() { - Blackprint.RegisterNode("Example/Math/Multiply", &engine.NodeMetadata{ + Blackprint.RegisterNode("Example/Math/Multiply", &engine.NodeRegister{ Input: engine.NodePortTemplate{ "Exec": engine.Ports.Trigger(func(port *engine.Port) { port.Iface.Node.Output["Result"].Set(port.Iface.Node.Embed.(*MathMultiple).Multiply()) @@ -41,12 +41,9 @@ func init() { Output: engine.NodePortTemplate{ "Result": types.Int, }, - }, - func(instance *engine.Instance) *engine.Node { - node := &engine.Node{ - Instance: instance, - Embed: &MathMultiple{}, - } + + Constructor: func(node *engine.Node) { + node.Embed = &MathMultiple{} iface := node.SetInterface() iface.Title = "Multiply" @@ -55,9 +52,8 @@ func init() { ev := event.(engine.CableEvent) log.Printf("\x1b[1m\x1b[33mMath\\Multiply:\x1b[0m \x1b[33mCable connected from %s (%s) to %s (%s)\x1b[0m\n", ev.Port.Iface.Title, ev.Port.Name, ev.Target.Iface.Title, ev.Target.Name) }) - - return node - }) + }, + }) } // ============ MathRandom Node ============ @@ -83,7 +79,7 @@ func (this *MathRandom) Request(cable *engine.Cable) { } func init() { - Blackprint.RegisterNode("Example/Math/Random", &engine.NodeMetadata{ + Blackprint.RegisterNode("Example/Math/Random", &engine.NodeRegister{ Input: engine.NodePortTemplate{ "Re-seed": engine.Ports.Trigger(func(port *engine.Port) { node := port.Iface.Node @@ -94,20 +90,15 @@ func init() { node.Output["Out"].Set(int(binary.BigEndian.Uint16(byt[:])) % 100) }), }, - Output: engine.NodePortTemplate{ "Out": types.Int, }, - }, - func(instance *engine.Instance) *engine.Node { - node := &engine.Node{ - Instance: instance, - Embed: &MathRandom{}, - } + + Constructor: func(node *engine.Node) { + node.Embed = &MathRandom{} iface := node.SetInterface() iface.Title = "Random" - - return node - }) + }, + }) } From f197f4a754babc73da964e8009fef0b842b63ae6 Mon Sep 17 00:00:00 2001 From: StefansArya Date: Fri, 9 Sep 2022 23:02:00 +0700 Subject: [PATCH 13/15] Make some types private --- blackprint/blackprint.go | 1 + engine/bpVar.go | 2 +- engine/cable.go | 2 +- engine/engine.go | 54 ++++++++++++------------ engine/interface.go | 22 +++++----- engine/node.go | 30 ++++++------- engine/nodesBPFunction.go | 86 +++++++++++++++++++------------------- engine/nodesBPVariable.go | 8 ++-- engine/nodesEnvironment.go | 4 +- engine/nodesFnPortVar.go | 16 +++---- engine/port.go | 20 ++++----- engine/portGetterSetter.go | 16 +++---- engine/portTypes.go | 28 ++++++------- engine/references.go | 4 +- engine/routePort.go | 18 ++++---- example/button.go | 4 +- example/input.go | 2 +- example/logger.go | 4 +- example/math.go | 12 +++--- 19 files changed, 167 insertions(+), 166 deletions(-) diff --git a/blackprint/blackprint.go b/blackprint/blackprint.go index 83d4f9f..7bb4ddb 100644 --- a/blackprint/blackprint.go +++ b/blackprint/blackprint.go @@ -22,3 +22,4 @@ func RegisterInterface(namespace string, meta *engine.InterfaceRegister) { var Event = engine.Event var Environment = engine.QEnvironment +var Port = engine.QPorts diff --git a/engine/bpVar.go b/engine/bpVar.go index 9be1d9e..93149ed 100644 --- a/engine/bpVar.go +++ b/engine/bpVar.go @@ -27,7 +27,7 @@ type BPVariable struct { Used []*Interface Value bpVarValue Listener []*Interface - FuncInstance *BPFunction // for shared function variables + FuncInstance *bpFunction // for shared function variables } func (b *BPVariable) Destroy() { diff --git a/engine/cable.go b/engine/cable.go index d185703..99ef712 100644 --- a/engine/cable.go +++ b/engine/cable.go @@ -28,7 +28,7 @@ type CableEvent struct { type PortValueEvent = CableEvent -func NewCable(owner *Port, target *Port) *Cable { +func newCable(owner *Port, target *Port) *Cable { var input *Port var output *Port diff --git a/engine/engine.go b/engine/engine.go index 026820a..44e1469 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -13,7 +13,7 @@ import ( var Event = &CustomEvent{} -type NodePortTemplate map[string]any // any = reflect.Kind | portFeature +type PortTemplate map[string]any // any = reflect.Kind | portFeature type Instance struct { *CustomEvent Iface map[string]*Interface // Storing with node id if exist @@ -23,13 +23,13 @@ type Instance struct { PanicOnError bool Variables map[string]*BPVariable - Functions map[string]*BPFunction + Functions map[string]*bpFunction Ref map[string]*referencesShortcut // For internal library use only SharedVariables map[string]*BPVariable QFuncMain *Interface - QFuncInstance *BPFunction + QFuncInstance *bpFunction QMainInstance *Instance QRemote any } @@ -43,29 +43,29 @@ func New() *Instance { } } -type Data struct { +type dataX struct { Value string `json:"value"` } -type Namespace string -type NodeData struct { - Data Data `json:"data,omitempty"` +type nodeData struct { + Data dataX `json:"data,omitempty"` } -type NodeOutput struct { +type nodeOutput struct { Output []Node `json:"output"` } -type NodeX struct { +type nodeX struct { Name string `json:"name"` I *int64 `json:"i,omitempty"` ID *string `json:"id,omitempty"` - NodeData - NodeOutput + nodeData + nodeOutput } -type DataStructure map[Namespace][]NodeX +type namespace string +type dataStructure map[namespace][]nodeX // -type SingleInstanceJSON map[string]any // any = nodeList | metadataValue +type singleInstanceJSON map[string]any // any = nodeList | metadataValue type metadataValue map[string]any type nodeList []nodeConfig type nodeConfig struct { @@ -105,7 +105,7 @@ type ImportOptions struct { } func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inserted []*Interface, err error) { - var data SingleInstanceJSON + var data singleInstanceJSON err = json.Unmarshal(str, &data) if err != nil { @@ -115,7 +115,7 @@ func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inse return instance.ImportJSONParsed(data, options...) } -func (instance *Instance) ImportJSONParsed(data SingleInstanceJSON, options ...ImportOptions) (inserted []*Interface, err error) { +func (instance *Instance) ImportJSONParsed(data singleInstanceJSON, options ...ImportOptions) (inserted []*Interface, err error) { hasOption := len(options) != 0 options_ := options[0] @@ -194,7 +194,7 @@ func (instance *Instance) ImportJSONParsed(data SingleInstanceJSON, options ...I if linkPortA == nil { if iface.QEnum == nodes.BPFnInput { target := instance.QGetTargetPortType(iface.Node.Instance, "input", ports) - linkPortA = iface.Embed.(*QBpFnInOut).AddPort(target, portName) + linkPortA = iface.Embed.(*qBpFnInOut).AddPort(target, portName) if linkPortA == nil { panic(fmt.Sprintf("Can't create output port (%s) for function (%s)", portName, iface.QFuncMain.Node.QFuncInstance.Id)) @@ -221,7 +221,7 @@ func (instance *Instance) ImportJSONParsed(data SingleInstanceJSON, options ...I targetTitle := targetNode.Title if targetNode.QEnum == nodes.BPFnOutput { - linkPortB = targetNode.Embed.(*QBpFnInOut).AddPort(linkPortA, portName) + linkPortB = targetNode.Embed.(*qBpFnInOut).AddPort(linkPortA, portName) if linkPortB == nil { panic(fmt.Sprintf("Can't create output port (%s) for function (%s)", portName, targetNode.QFuncMain.Node.QFuncInstance.Id)) @@ -271,7 +271,7 @@ func (instance *Instance) QGetTargetPortType(ins *Instance, which string, target } } -type EvNodeDelete struct { +type NodeDeleteEvent struct { Iface any } @@ -283,7 +283,7 @@ func (instance *Instance) DeleteNode(iface *Interface) { instance.IfaceList = utils.RemoveItemAtIndex(instance.IfaceList, i) - eventData := &EvNodeDelete{ + eventData := &NodeDeleteEvent{ Iface: iface, } instance.Emit("node.delete", eventData) @@ -487,10 +487,10 @@ type funcOptions struct { Title string `json:"title"` Vars []string `json:"vars"` PrivateVars []string `json:"privateVars"` - Structure SingleInstanceJSON `json:"structure"` + Structure singleInstanceJSON `json:"structure"` } -func (instance *Instance) CreateFunction(id string, options any) *BPFunction { +func (instance *Instance) CreateFunction(id string, options any) *bpFunction { id = createBPVariableRegx.ReplaceAllString(id, "_") if old, exist := instance.Functions[id]; exist { @@ -503,21 +503,21 @@ func (instance *Instance) CreateFunction(id string, options any) *BPFunction { // This will be updated if the function sketch was modified structure := options_.Structure if structure == nil { - structure = SingleInstanceJSON{ + structure = singleInstanceJSON{ "BP/Fn/Input": nodeList{nodeConfig{I: 0}}, "BP/Fn/Output": nodeList{nodeConfig{I: 1}}, } } title := id - temp := &BPFunction{ + temp := &bpFunction{ Id: id, Title: title, Type: 0, // Type not set Structure: structure, RootInstance: instance, - Input: NodePortTemplate{}, - Output: NodePortTemplate{}, + Input: PortTemplate{}, + Output: PortTemplate{}, } meta := &NodeRegister{ @@ -534,10 +534,10 @@ func (instance *Instance) CreateFunction(id string, options any) *BPFunction { QFuncInstance: temp, } - node.Embed = &BPFunctionNode{} + node.Embed = &bpFunctionNode{} iface := node.SetInterface("BPIC/BP/Fn/Main") - iface.Embed.(*BPFunctionNode).Type = "function" + iface.Embed.(*bpFunctionNode).Type = "function" iface.QEnum = nodes.BPFnMain iface.Namespace = id iface.Title = title diff --git a/engine/interface.go b/engine/interface.go index 2756315..f02c8d9 100644 --- a/engine/interface.go +++ b/engine/interface.go @@ -35,7 +35,7 @@ type Interface struct { *CustomEvent Id string - uniqId int // For BPFunction only + uniqId int // For bpFunction only I int // index Title string Namespace string @@ -85,11 +85,11 @@ func (iface *Interface) QPrepare(meta *NodeRegister) { node.Ref = ref iface.Ref = ref - node.Routes = &RoutePort{Iface: iface} + node.Routes = &routePort{Iface: iface} for i := 0; i < 3; i++ { which := portList[i] - port := utils.GetProperty(meta, which).(NodePortTemplate) // get value by property name + port := utils.GetProperty(meta, which).(PortTemplate) // get value by property name if port == nil { continue @@ -97,18 +97,18 @@ func (iface *Interface) QPrepare(meta *NodeRegister) { ifacePort := map[string]*Port{} - var inputUpgradePort map[string]*PortInputGetterSetter - var outputUpgradePort map[string]*PortOutputGetterSetter + var inputUpgradePort map[string]*portInputGetterSetter + var outputUpgradePort map[string]*portOutputGetterSetter if which == "Input" { - inputUpgradePort = map[string]*PortInputGetterSetter{} + inputUpgradePort = map[string]*portInputGetterSetter{} ref.Input = inputUpgradePort ref.IInput = ifacePort iface.Input = ifacePort node.Input = inputUpgradePort } else { - outputUpgradePort = map[string]*PortOutputGetterSetter{} + outputUpgradePort = map[string]*portOutputGetterSetter{} ref.Output = outputUpgradePort ref.IOutput = ifacePort @@ -123,16 +123,16 @@ func (iface *Interface) QPrepare(meta *NodeRegister) { // CreateLinker() if which == "Input" { - inputUpgradePort[name] = &PortInputGetterSetter{port: linkedPort} + inputUpgradePort[name] = &portInputGetterSetter{port: linkedPort} } else { - outputUpgradePort[name] = &PortOutputGetterSetter{port: linkedPort} + outputUpgradePort[name] = &portOutputGetterSetter{port: linkedPort} } } } } func (iface *Interface) QCreatePort(which string, name string, config_ any) *Port { - var config *PortFeature + var config *portFeature var type_ reflect.Kind var types_ []reflect.Kind var feature int @@ -160,7 +160,7 @@ func (iface *Interface) QCreatePort(which string, name string, config_ any) *Por panic(iface.Namespace + ": '" + name + "' Port type(" + type_.String() + ") for initialization was not recognized") } } else { - config = config_.(*PortFeature) + config = config_.(*portFeature) type_ = config.Type feature = config.Id diff --git a/engine/node.go b/engine/node.go index e3d273b..c73b44d 100644 --- a/engine/node.go +++ b/engine/node.go @@ -32,19 +32,19 @@ type Node struct { Instance *Instance Iface *Interface DisablePorts bool - Routes *RoutePort + Routes *routePort Embed embedNode Ref *referencesShortcut - Output map[string]*PortOutputGetterSetter - Input map[string]*PortInputGetterSetter + Output map[string]*portOutputGetterSetter + Input map[string]*portInputGetterSetter // Property map[string]getterSetter // For internal library use only - QFuncInstance *BPFunction - RefOutput map[string]*PortOutputGetterSetter - // RefInput map[string]*PortInputGetterSetter + QFuncInstance *bpFunction + RefOutput map[string]*portOutputGetterSetter + // RefInput map[string]*portInputGetterSetter } // Proxies, for library only @@ -57,19 +57,19 @@ func (n *Node) SyncIn(id string, data ...any) { n.Embed.SyncIn(id, data) } type NodeRegister struct { // Port Template - Output NodePortTemplate - Input NodePortTemplate - // Property *NodePortTemplate + Output PortTemplate + Input PortTemplate + // Property *PortTemplate - Constructor NodeConstructor + Constructor nodeConstructor } type InterfaceRegister struct { - Constructor InterfaceConstructor + Constructor interfaceConstructor } -type NodeConstructor func(*Node) -type InterfaceConstructor func(*Interface) +type nodeConstructor func(*Node) +type interfaceConstructor func(*Interface) // QNodeList = Private function, for internal library only var QNodeList = map[string]*NodeRegister{} @@ -110,11 +110,11 @@ func (n *Node) CreatePort(which string, name string, config_ any) *Port { if which != "input" { ifacePort := n.Iface.Input ifacePort[name] = port - n.Input[name] = &PortInputGetterSetter{port: port} + n.Input[name] = &portInputGetterSetter{port: port} } else if which != "output" { ifacePort := n.Iface.Output ifacePort[name] = port - n.Output[name] = &PortOutputGetterSetter{port: port} + n.Output[name] = &portOutputGetterSetter{port: port} } else { panic("Can only create port for 'input' and 'output'") } diff --git a/engine/nodesBPFunction.go b/engine/nodesBPFunction.go index 367f7ab..fca8fb6 100644 --- a/engine/nodesBPFunction.go +++ b/engine/nodesBPFunction.go @@ -11,23 +11,23 @@ import ( ) // Main function node -type BPFunctionNode struct { // Main function node -> BPI/F/{FunctionName} +type bpFunctionNode struct { // Main function node -> BPI/F/{FunctionName} *EmbedNode Type string } -func (b *BPFunctionNode) Init() { +func (b *bpFunctionNode) Init() { if b.Iface.Embed.(*FnMain).QImportOnce { b.Iface.QBpFnInit() } } -func (b *BPFunctionNode) Imported(data map[string]any) { +func (b *bpFunctionNode) Imported(data map[string]any) { ins := b.Node.QFuncInstance ins.Used = append(ins.Used, b.Node.Iface) } -func (b *BPFunctionNode) Update(cable *Cable) { +func (b *bpFunctionNode) Update(cable *Cable) { iface := b.Iface.QProxyInput.Iface Output := iface.Node.Output @@ -50,21 +50,21 @@ func (b *BPFunctionNode) Update(cable *Cable) { Output[cable.Input.Name].Set(cable.GetValue()) } -func (b *BPFunctionNode) Destroy() { +func (b *bpFunctionNode) Destroy() { ins := b.Node.QFuncInstance utils.RemoveItem(ins.Used, b.Node.Iface) } // used for instance.createFunction -type BPFunction struct { // <= _funcInstance +type bpFunction struct { // <= _funcInstance *CustomEvent Id string Title string Type int Used []*Interface - Input NodePortTemplate - Output NodePortTemplate - Structure SingleInstanceJSON + Input PortTemplate + Output PortTemplate + Structure singleInstanceJSON Variables map[string]*BPVariable PrivateVars []string RootInstance *Instance @@ -74,7 +74,7 @@ type BPFunction struct { // <= _funcInstance QSyncing bool } -func (b *BPFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { +func (b *bpFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { for _, iface_ := range b.Used { if iface_.Node == fromNode { continue @@ -120,7 +120,7 @@ func (b *BPFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { if targetInput == nil { if inputIface.QEnum == nodes.BPFnOutput { - targetInput = inputIface.Embed.(*QBpFnInOut).AddPort(targetOutput, output.Name) + targetInput = inputIface.Embed.(*qBpFnInOut).AddPort(targetOutput, output.Name) } else { panic("Output port was not found") } @@ -128,7 +128,7 @@ func (b *BPFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { if targetOutput == nil { if outputIface.QEnum == nodes.BPFnInput { - targetOutput = outputIface.Embed.(*QBpFnInOut).AddPort(targetInput, input.Name) + targetOutput = outputIface.Embed.(*qBpFnInOut).AddPort(targetInput, input.Name) } else { panic("Input port was not found") } @@ -172,7 +172,7 @@ func (b *BPFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { } } -// func (b *BPFunction) CreateNode(instance *Instance, options nodeConfig) (*Interface, []*Interface) { +// func (b *bpFunction) CreateNode(instance *Instance, options nodeConfig) (*Interface, []*Interface) { // return instance.CreateNode(b.Node, options, nil) // } @@ -180,7 +180,7 @@ type FnVarOptions struct { Scope int } -func (b *BPFunction) CreateVariable(id string, options FnVarOptions) *BPVariable { +func (b *bpFunction) CreateVariable(id string, options FnVarOptions) *BPVariable { if _, exist := b.Variables[id]; exist { panic("Variable id already exist: id") } @@ -205,19 +205,19 @@ func (b *BPFunction) CreateVariable(id string, options FnVarOptions) *BPVariable return temp } -type EvVariableNew struct { +type VariableNewEvent struct { Id string ScopeId int } -func (b *BPFunction) AddPrivateVars(id string) { +func (b *bpFunction) AddPrivateVars(id string) { if utils.Contains(b.PrivateVars, id) { return } b.PrivateVars = append(b.PrivateVars, id) - temp := &EvVariableNew{ + temp := &VariableNewEvent{ ScopeId: VarScopePrivate, Id: id, } @@ -229,15 +229,15 @@ func (b *BPFunction) AddPrivateVars(id string) { } } -func (b *BPFunction) RefreshPrivateVars(instance *Instance) { +func (b *bpFunction) RefreshPrivateVars(instance *Instance) { vars := instance.Variables for _, id := range b.PrivateVars { vars[id] = &BPVariable{Id: id} } } -func (b *BPFunction) RenamePort(which string, fromName string, toName string) { - var main NodePortTemplate +func (b *bpFunction) RenamePort(which string, fromName string, toName string) { + var main PortTemplate var proxyPort string if which == "output" { main = b.Output @@ -281,17 +281,17 @@ func (b *BPFunction) RenamePort(which string, fromName string, toName string) { } } -func (b *BPFunction) Destroy() { +func (b *bpFunction) Destroy() { for _, iface := range b.Used { iface.Node.Instance.DeleteNode(iface) } } -type QNodeInput struct { +type qNodeInput struct { *EmbedNode } -func (n *QNodeInput) imported(data any) { +func (n *qNodeInput) Imported(data map[string]any) { input := n.Iface.QFuncMain.Node.QFuncInstance.Input for key, value := range input { @@ -299,18 +299,18 @@ func (n *QNodeInput) imported(data any) { } } -func (n *QNodeInput) request(cable *Cable) { +func (n *qNodeInput) Request(cable *Cable) { name := cable.Output.Name // This will trigger the port to request from outside and assign to this node's port n.Node.Output[name].Set(n.Iface.QFuncMain.Node.Input[name].Get()) } -type QNodeOutput struct { +type qNodeOutput struct { *EmbedNode } -func (n *QNodeOutput) imported(data map[string]any) { +func (n *qNodeOutput) Imported(data map[string]any) { output := n.Iface.QFuncMain.Node.QFuncInstance.Output for key, value := range output { @@ -318,7 +318,7 @@ func (n *QNodeOutput) imported(data map[string]any) { } } -func (n *QNodeOutput) update(cable *Cable) { +func (n *qNodeOutput) Update(cable *Cable) { iface := n.Iface.QFuncMain if cable == nil { // Triggered by port route IOutput := iface.Output @@ -377,7 +377,7 @@ func (f *FnMain) QBpFnInit() { f.QPortSw_ = nil InputIface := f.Iface.QProxyInput.Iface - InputIface_ := InputIface.Embed.(*QBpFnInOut) + InputIface_ := InputIface.Embed.(*qBpFnInOut) if InputIface_.QPortSw_ != nil { InputIface.QInitPortSwitches(InputIface_.QPortSw_) @@ -405,7 +405,7 @@ func (f *FnMain) RenamePort(which string, fromName string, toName string) { f.QSave(false, "", true) } -type QBpFnInOut struct { +type qBpFnInOut struct { *EmbedInterface Type string QPortSw_ map[string]int @@ -416,7 +416,7 @@ type addPortRef struct { Port *Port } -func (b *QBpFnInOut) AddPort(port *Port, customName string) *Port { +func (b *qBpFnInOut) AddPort(port *Port, customName string) *Port { if port == nil { panic("Can't set type with nil") } @@ -438,7 +438,7 @@ func (b *QBpFnInOut) AddPort(port *Port, customName string) *Port { var portType any if port.Feature == PortTypeTrigger { reff = &addPortRef{} - portType = Ports.Trigger(func(*Port) { + portType = QPorts.Trigger(func(*Port) { reff.Node.Output[reff.Port.Name].Call() }) } else { @@ -488,7 +488,7 @@ func (b *QBpFnInOut) AddPort(port *Port, customName string) *Port { var inputPort *Port if portType == types.Function { - inputPort = nodeA.CreatePort("input", name, Ports.Trigger(outputPort.QCallAll)) + inputPort = nodeA.CreatePort("input", name, QPorts.Trigger(outputPort.QCallAll)) } else { inputPort = nodeA.CreatePort("input", name, portType) } @@ -499,7 +499,7 @@ func (b *QBpFnInOut) AddPort(port *Port, customName string) *Port { } if b.Type == "bp-fn-input" { - outputPort.Name_ = &RefPortName{Name: name} // When renaming port, this also need to be changed + outputPort.Name_ = &refPortName{Name: name} // When renaming port, this also need to be changed b.Iface.Emit("_add.{name}", outputPort) inputPort.On("value", func(ev PortValueEvent) { @@ -509,12 +509,12 @@ func (b *QBpFnInOut) AddPort(port *Port, customName string) *Port { return outputPort } - inputPort.Name_ = &RefPortName{Name: name} // When renaming port, this also need to be changed + inputPort.Name_ = &refPortName{Name: name} // When renaming port, this also need to be changed b.Iface.Emit("_add.{name}", inputPort) return inputPort } -func (b *QBpFnInOut) renamePort(fromName string, toName string) { +func (b *qBpFnInOut) RenamePort(fromName string, toName string) { bpFunction := b.Iface.QFuncMain.Node.QFuncInstance // Main (input) -> Input (output) if b.Type == "bp-fn-input" { @@ -524,7 +524,7 @@ func (b *QBpFnInOut) renamePort(fromName string, toName string) { } } -func (b *QBpFnInOut) deletePort(name string) { +func (b *qBpFnInOut) DeletePort(name string) { funcMainNode := b.Iface.QFuncMain.Node if b.Type == "bp-fn-input" { // Main (input) -> Input (output) funcMainNode.DeletePort("input", name) @@ -539,16 +539,16 @@ func (b *QBpFnInOut) deletePort(name string) { func init() { QNodeList["BP/Fn/Input"] = &NodeRegister{ - Output: NodePortTemplate{}, + Output: PortTemplate{}, Constructor: func(node *Node) { - node.Embed = &QNodeInput{} + node.Embed = &qNodeInput{} iface := node.SetInterface("BPIC/BP/Fn/Input") iface.QEnum = nodes.BPFnInput iface.QDynamicPort = true // Port is initialized dynamically iface.Title = "Input" - iface.Embed.(*QBpFnInOut).Type = "bp-fn-input" + iface.Embed.(*qBpFnInOut).Type = "bp-fn-input" iface.QFuncMain = node.Instance.QFuncMain iface.QFuncMain.QProxyInput = node }, @@ -556,12 +556,12 @@ func init() { QInterfaceList["BPIC/BP/Fn/Input"] = &InterfaceRegister{ Constructor: func(iface *Interface) { - iface.Embed = &QBpFnInOut{} + iface.Embed = &qBpFnInOut{} }, } QNodeList["BP/Fn/Output"] = &NodeRegister{ - Input: NodePortTemplate{}, + Input: PortTemplate{}, Constructor: func(node *Node) { node.Embed = &bpVarGet{} @@ -570,7 +570,7 @@ func init() { iface.QDynamicPort = true // Port is initialized dynamically iface.Title = "Output" - iface.Embed.(*QBpFnInOut).Type = "bp-fn-output" + iface.Embed.(*qBpFnInOut).Type = "bp-fn-output" iface.QFuncMain = node.Instance.QFuncMain iface.QFuncMain.QProxyOutput = node }, @@ -578,7 +578,7 @@ func init() { QInterfaceList["BPIC/BP/Fn/Output"] = &InterfaceRegister{ Constructor: func(iface *Interface) { - iface.Embed = &QBpFnInOut{} + iface.Embed = &qBpFnInOut{} }, } diff --git a/engine/nodesBPVariable.go b/engine/nodesBPVariable.go index 0ed9652..50f8143 100644 --- a/engine/nodesBPVariable.go +++ b/engine/nodesBPVariable.go @@ -54,7 +54,7 @@ func (b *bpVarGetSet) ChangeVar(name string, scopeId int) map[string]*BPVariable thisInstance := b.Node.Instance funcInstance := thisInstance.QFuncMain - var bpFunc *BPFunction + var bpFunc *bpFunction if funcInstance != nil { bpFunc = funcInstance.Node.QFuncInstance } @@ -231,7 +231,7 @@ func (b *iVarGet) QReinitPort() *Port { } if temp.Type == types.Function { - node.CreatePort("Input", "Val", Ports.Trigger(func(p *Port) { + node.CreatePort("Input", "Val", QPorts.Trigger(func(p *Port) { temp.Emit("call", nil) })) } else { @@ -243,7 +243,7 @@ func (b *iVarGet) QReinitPort() *Port { func init() { QNodeList["BP/Var/Set"] = &NodeRegister{ - Input: NodePortTemplate{}, + Input: PortTemplate{}, Constructor: func(node *Node) { node.Embed = &bpVarSet{} @@ -271,7 +271,7 @@ func init() { } QNodeList["BP/Var/Get"] = &NodeRegister{ - Output: NodePortTemplate{}, + Output: PortTemplate{}, Constructor: func(node *Node) { node.Embed = &bpVarGet{} diff --git a/engine/nodesEnvironment.go b/engine/nodesEnvironment.go index cc1220d..23497c3 100644 --- a/engine/nodesEnvironment.go +++ b/engine/nodesEnvironment.go @@ -70,7 +70,7 @@ type iEnvSet struct { func init() { QNodeList["BP/Env/Get"] = &NodeRegister{ - Output: NodePortTemplate{ + Output: PortTemplate{ "Val": types.String, }, Constructor: func(node *Node) { @@ -98,7 +98,7 @@ func init() { } QNodeList["BP/Env/Set"] = &NodeRegister{ - Input: NodePortTemplate{ + Input: PortTemplate{ "Val": types.String, }, Constructor: func(node *Node) { diff --git a/engine/nodesFnPortVar.go b/engine/nodesFnPortVar.go index 717202b..02f3382 100644 --- a/engine/nodesFnPortVar.go +++ b/engine/nodesFnPortVar.go @@ -77,13 +77,13 @@ func (f *fnVarInputIface) Imported(data map[string]any) { cable.Disconnect() node.DeletePort("output", "Val") - portName := &RefPortName{Name: name} + portName := &refPortName{Name: name} portType := getFnPortType(port, "input", f.QParentFunc, portName) newPort := node.CreatePort("output", "Val", portType) newPort.Name_ = portName newPort.ConnectPort(port) - proxyIface.Embed.(*QBpFnInOut).AddPort(port, name) + proxyIface.Embed.(*qBpFnInOut).AddPort(port, name) f.QAddListener() return true @@ -194,13 +194,13 @@ func (f *fnVarOutputIface) Imported(data map[string]any) { cable.Disconnect() node.DeletePort("input", "Val") - portName := &RefPortName{Name: name} + portName := &refPortName{Name: name} portType := getFnPortType(port, "output", f.QParentFunc, portName) newPort := node.CreatePort("input", "Val", portType) newPort.Name_ = portName newPort.ConnectPort(port) - proxyIface.Embed.(*QBpFnInOut).AddPort(port, name) + proxyIface.Embed.(*qBpFnInOut).AddPort(port, name) return true } @@ -235,12 +235,12 @@ func (f *fnVarOutputIface) Imported(data map[string]any) { } } -func getFnPortType(port *Port, which string, parentNode *Interface, ref *RefPortName) any { +func getFnPortType(port *Port, which string, parentNode *Interface, ref *refPortName) any { if port.Feature == PortTypeTrigger { if which == "input" { // Function Input (has output port inside, and input port on main node) return types.Function } else { - return Ports.Trigger(parentNode.Output[ref.Name].QCallAll) + return QPorts.Trigger(parentNode.Output[ref.Name].QCallAll) } } else { if port.Feature != 0 { @@ -253,7 +253,7 @@ func getFnPortType(port *Port, which string, parentNode *Interface, ref *RefPort func init() { QNodeList["BP/FnVar/Input"] = &NodeRegister{ - Output: NodePortTemplate{}, + Output: PortTemplate{}, Constructor: func(node *Node) { node.Embed = &fnVarInput{} @@ -280,7 +280,7 @@ func init() { } QNodeList["BP/FnVar/Output"] = &NodeRegister{ - Input: NodePortTemplate{}, + Input: PortTemplate{}, Constructor: func(node *Node) { node.Embed = &fnVarOutput{} diff --git a/engine/port.go b/engine/port.go index 52504a4..52c1b6b 100644 --- a/engine/port.go +++ b/engine/port.go @@ -18,7 +18,7 @@ type PortStructTemplate struct { type Port struct { CustomEvent Name string - Name_ *RefPortName // For BPFunction only, ToDo: fill alternate name, search in engine-php _name for hints + Name_ *refPortName // For bpFunction only, ToDo: fill alternate name, search in engine-php _name for hints Type reflect.Kind Types []reflect.Kind Cables []*Cable @@ -28,13 +28,13 @@ type Port struct { Value any // Dynamic data (depend on Type) for storing port value (int, string, map, etc..) Sync bool Feature int - QFeature *PortFeature // For caching the configuration + QFeature *portFeature // For caching the configuration Struct map[string]PortStructTemplate Splitted bool AllowResync bool // Retrigger connected node's .update when the output value is similar // Only in Golang we need to do this '-' - RoutePort *RoutePort + RoutePort *routePort // Internal/Private property QCache any @@ -48,8 +48,8 @@ type Port struct { } /** For internal library use only */ -// For BPFunction only -type RefPortName struct { +// For bpFunction only +type refPortName struct { Name string } @@ -69,7 +69,7 @@ const ( ) // Port feature -type PortFeature struct { +type portFeature struct { Id int Type reflect.Kind Types []reflect.Kind @@ -77,7 +77,7 @@ type PortFeature struct { Func func(*Port) } -func (port *Port) QGetPortFeature() *PortFeature { +func (port *Port) QGetPortFeature() *portFeature { return port.QFeature } func (port *Port) DisconnectAll() { @@ -94,10 +94,10 @@ func (port *Port) DisconnectAll() { // ./portGetterSetter.go func (port *Port) CreateLinker() getterSetter { if port.Source == PortInput { - return &PortInputGetterSetter{port: port} + return &portInputGetterSetter{port: port} } - return &PortOutputGetterSetter{port: port} + return &portOutputGetterSetter{port: port} } func (port *Port) sync() { @@ -345,7 +345,7 @@ func (port *Port) ConnectCable(cable *Cable) bool { return true } func (port *Port) ConnectPort(portTarget *Port) bool { - cable := NewCable(portTarget, port) + cable := newCable(portTarget, port) if portTarget.QGhost { cable.QGhost = true } diff --git a/engine/portGetterSetter.go b/engine/portGetterSetter.go index 85a1de1..8ca0ccd 100644 --- a/engine/portGetterSetter.go +++ b/engine/portGetterSetter.go @@ -4,21 +4,21 @@ import ( "github.com/blackprint/engine-go/types" ) -type PortInputGetterSetter struct { +type portInputGetterSetter struct { getterSetter port *Port } -func (gs *PortInputGetterSetter) Set(val any) { +func (gs *portInputGetterSetter) Set(val any) { panic("Can't set input port's value") } -func (gs *PortInputGetterSetter) Call() { +func (gs *portInputGetterSetter) Call() { gs.port.QFunc(gs.port) gs.port.Iface.Node.Routes.RouteOut() } -func (gs *PortInputGetterSetter) Get() any { +func (gs *portInputGetterSetter) Get() any { port := gs.port // This port must use values from connected output @@ -106,12 +106,12 @@ func (gs *PortInputGetterSetter) Get() any { return data } -type PortOutputGetterSetter struct { +type portOutputGetterSetter struct { getterSetter port *Port } -func (gs *PortOutputGetterSetter) Set(val any) { +func (gs *portOutputGetterSetter) Set(val any) { port := gs.port if port.Source == PortInput { @@ -130,7 +130,7 @@ func (gs *PortOutputGetterSetter) Set(val any) { // createCallablePort // createCallableRoutePort -func (gs *PortOutputGetterSetter) Call() { +func (gs *portOutputGetterSetter) Call() { if gs.port.Type == types.Route { cable := gs.port.Cables[0] if cable == nil { @@ -157,7 +157,7 @@ func (gs *PortOutputGetterSetter) Call() { } } -func (gs *PortOutputGetterSetter) Get() any { +func (gs *portOutputGetterSetter) Get() any { port := gs.port if port.Feature == PortTypeArrayOf { diff --git a/engine/portTypes.go b/engine/portTypes.go index d9cbfd9..3f23f77 100644 --- a/engine/portTypes.go +++ b/engine/portTypes.go @@ -6,10 +6,10 @@ import ( type portObject struct{} -var Ports *portObject +var QPorts *portObject func init() { - Ports = &portObject{} + QPorts = &portObject{} } /* This port can contain multiple cable as input @@ -17,8 +17,8 @@ func init() { * it's only one type, not union * for union port, please split it to different port to handle it */ -func (*portObject) ArrayOf(type_ reflect.Kind) *PortFeature { - return &PortFeature{ +func (*portObject) ArrayOf(type_ reflect.Kind) *portFeature { + return &portFeature{ Id: PortTypeArrayOf, Type: type_, } @@ -28,8 +28,8 @@ func (*portObject) ArrayOf(type_ reflect.Kind) *PortFeature { * type = Type Data that allowed for the Port * value = default value for the port */ -func (*portObject) Default(type_ reflect.Kind, val any) *PortFeature { - return &PortFeature{ +func (*portObject) Default(type_ reflect.Kind, val any) *portFeature { + return &portFeature{ Id: PortTypeDefault, Type: type_, Value: val, @@ -39,8 +39,8 @@ func (*portObject) Default(type_ reflect.Kind, val any) *PortFeature { /* This port will be used as a trigger or callable input port * func (*portObject) = callback when the port was being called as a function */ -func (*portObject) Trigger(callback func(*Port)) *PortFeature { - return &PortFeature{ +func (*portObject) Trigger(callback func(*Port)) *portFeature { + return &portFeature{ Id: PortTypeTrigger, Func: callback, } @@ -49,8 +49,8 @@ func (*portObject) Trigger(callback func(*Port)) *PortFeature { /* This port can allow multiple different types * like an 'any' port, but can only contain one value */ -func (*portObject) Union(types []reflect.Kind) *PortFeature { - return &PortFeature{ +func (*portObject) Union(types []reflect.Kind) *portFeature { + return &portFeature{ Id: PortTypeUnion, Types: types, } @@ -59,16 +59,16 @@ func (*portObject) Union(types []reflect.Kind) *PortFeature { /* This port can allow multiple different types * like an 'any' port, but can only contain one value */ -func (*portObject) StructOf(type_ reflect.Kind, structure map[string]PortStructTemplate) *PortFeature { - return &PortFeature{ +func (*portObject) StructOf(type_ reflect.Kind, structure map[string]PortStructTemplate) *portFeature { + return &portFeature{ Id: PortTypeStructOf, Type: type_, Value: structure, } } -func (*portObject) Route() *PortFeature { - return &PortFeature{ +func (*portObject) Route() *portFeature { + return &portFeature{ Id: PortTypeRoute, } } diff --git a/engine/references.go b/engine/references.go index 7b66f16..d9b9166 100644 --- a/engine/references.go +++ b/engine/references.go @@ -2,7 +2,7 @@ package engine type referencesShortcut struct { IInput map[string]*Port - Input map[string]*PortInputGetterSetter + Input map[string]*portInputGetterSetter IOutput map[string]*Port - Output map[string]*PortOutputGetterSetter + Output map[string]*portOutputGetterSetter } diff --git a/engine/routePort.go b/engine/routePort.go index cb9bb15..7e55d68 100644 --- a/engine/routePort.go +++ b/engine/routePort.go @@ -5,7 +5,7 @@ import ( "github.com/blackprint/engine-go/utils" ) -type RoutePort struct { +type routePort struct { *Port In []*Cable Out *Cable @@ -18,8 +18,8 @@ type RoutePort struct { QIsPaused bool } -func newRoutePort(iface *Interface) *RoutePort { - temp := &RoutePort{ +func newRoutePort(iface *Interface) *routePort { + temp := &routePort{ Iface: iface, IsRoute: true, } @@ -30,13 +30,13 @@ func newRoutePort(iface *Interface) *RoutePort { } // Connect other route port (this .out to other .in port) -func (r *RoutePort) RouteTo(iface *Interface) { +func (r *routePort) RouteTo(iface *Interface) { if r.Out != nil { r.Out.Disconnect() } if iface == nil { - cable := NewCable(r.Port, nil) + cable := newCable(r.Port, nil) cable.IsRoute = true r.Out = cable return @@ -44,7 +44,7 @@ func (r *RoutePort) RouteTo(iface *Interface) { port := iface.Node.Routes - cable := NewCable(r.Port, port.Port) + cable := newCable(r.Port, port.Port) cable.IsRoute = true cable.Output = r.Port r.Out = cable @@ -53,7 +53,7 @@ func (r *RoutePort) RouteTo(iface *Interface) { cable.QConnected() } -func (r *RoutePort) ConnectCable(cable *Cable) bool { +func (r *routePort) ConnectCable(cable *Cable) bool { if utils.Contains(r.In, cable) { return false } @@ -66,7 +66,7 @@ func (r *RoutePort) ConnectCable(cable *Cable) bool { return true } -func (r *RoutePort) RouteIn(cable *Cable) { +func (r *routePort) RouteIn(cable *Cable) { node := r.Iface.Node node.Update(cable) @@ -74,7 +74,7 @@ func (r *RoutePort) RouteIn(cable *Cable) { routes.RouteOut() } -func (r *RoutePort) RouteOut() { +func (r *routePort) RouteOut() { if r.DisableOut { return } diff --git a/example/button.go b/example/button.go index 02aaa90..a4f49c1 100644 --- a/example/button.go +++ b/example/button.go @@ -24,8 +24,8 @@ func (iface *ButtonSimpleIFace) Clicked(ev any) { // This will be called from example.go func init() { Blackprint.RegisterNode("Example/Button/Simple", &engine.NodeRegister{ - Output: engine.NodePortTemplate{}, - Input: engine.NodePortTemplate{}, + Output: engine.PortTemplate{}, + Input: engine.PortTemplate{}, Constructor: func(node *engine.Node) { node.Embed = &ButtonSimple{} diff --git a/example/input.go b/example/input.go index bcf0203..4273d98 100644 --- a/example/input.go +++ b/example/input.go @@ -59,7 +59,7 @@ func (gs *MyData) Get() any { // This will be called from example.go func init() { Blackprint.RegisterNode("Example/Input/Simple", &engine.NodeRegister{ - Output: engine.NodePortTemplate{ + Output: engine.PortTemplate{ "Changed": types.Function, "Value": types.String, }, diff --git a/example/logger.go b/example/logger.go index 39fd041..3f489a3 100644 --- a/example/logger.go +++ b/example/logger.go @@ -66,8 +66,8 @@ func (iface *LoggerIFace) Log(val ...any) any { func init() { Blackprint.RegisterNode("Example/Display/Logger", &engine.NodeRegister{ - Input: engine.NodePortTemplate{ - "Any": engine.Ports.ArrayOf(types.Any), // nil => Any + Input: engine.PortTemplate{ + "Any": Blackprint.Port.ArrayOf(types.Any), // nil => Any }, Constructor: func(node *engine.Node) { diff --git a/example/math.go b/example/math.go index 55665cb..97894f3 100644 --- a/example/math.go +++ b/example/math.go @@ -29,8 +29,8 @@ func (this *MathMultiple) Update(cable *engine.Cable) { func init() { Blackprint.RegisterNode("Example/Math/Multiply", &engine.NodeRegister{ - Input: engine.NodePortTemplate{ - "Exec": engine.Ports.Trigger(func(port *engine.Port) { + Input: engine.PortTemplate{ + "Exec": Blackprint.Port.Trigger(func(port *engine.Port) { port.Iface.Node.Output["Result"].Set(port.Iface.Node.Embed.(*MathMultiple).Multiply()) log.Printf("\x1b[1m\x1b[33mMath\\Multiply:\x1b[0m \x1b[33mResult has been set: %d\x1b[0m\n", port.Iface.Node.Output["Result"].Get()) }), @@ -38,7 +38,7 @@ func init() { "B": types.Any, }, - Output: engine.NodePortTemplate{ + Output: engine.PortTemplate{ "Result": types.Int, }, @@ -80,8 +80,8 @@ func (this *MathRandom) Request(cable *engine.Cable) { func init() { Blackprint.RegisterNode("Example/Math/Random", &engine.NodeRegister{ - Input: engine.NodePortTemplate{ - "Re-seed": engine.Ports.Trigger(func(port *engine.Port) { + Input: engine.PortTemplate{ + "Re-seed": Blackprint.Port.Trigger(func(port *engine.Port) { node := port.Iface.Node node.Embed.(*MathRandom).Executed = true @@ -90,7 +90,7 @@ func init() { node.Output["Out"].Set(int(binary.BigEndian.Uint16(byt[:])) % 100) }), }, - Output: engine.NodePortTemplate{ + Output: engine.PortTemplate{ "Out": types.Int, }, From b4b45d18122ff1a0c1ff39ec1a7935e59ad30526 Mon Sep 17 00:00:00 2001 From: StefansArya Date: Fri, 9 Sep 2022 23:39:45 +0700 Subject: [PATCH 14/15] Use underscore and lowercase for internal property --- engine/cable.go | 8 +- engine/engine.go | 64 ++++++++-------- engine/environment.go | 8 +- engine/interface.go | 38 +++++----- engine/node.go | 10 +-- engine/nodesBPFunction.go | 146 ++++++++++++++++++------------------- engine/nodesBPVariable.go | 78 ++++++++++---------- engine/nodesEnvironment.go | 14 ++-- engine/nodesFnPortVar.go | 110 ++++++++++++++-------------- engine/port.go | 62 ++++++++-------- engine/portFeature.go | 6 +- engine/portGetterSetter.go | 12 +-- engine/portGhost.go | 4 +- engine/routePort.go | 16 ++-- 14 files changed, 288 insertions(+), 288 deletions(-) diff --git a/engine/cable.go b/engine/cable.go index 99ef712..6161a1f 100644 --- a/engine/cable.go +++ b/engine/cable.go @@ -16,8 +16,8 @@ type Cable struct { Disabled int IsRoute bool Connected bool - QEvDisconnected bool - QGhost bool + _evDisconnected bool + _ghost bool } type CableEvent struct { @@ -50,7 +50,7 @@ func newCable(owner *Port, target *Port) *Cable { } } -func (c *Cable) QConnected() { +func (c *Cable) _connected() { c.Connected = true ownerEv := &CableEvent{ @@ -113,7 +113,7 @@ func (c *Cable) Disconnect(which_ ...*Port) { // which = port alreadyEmitToInstance := false if c.Input != nil { - c.Input.QCache = nil + c.Input._cache = nil } if c.Owner != nil && (!hasWhich || which == c.Owner) { diff --git a/engine/engine.go b/engine/engine.go index 44e1469..aebaf55 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -27,11 +27,11 @@ type Instance struct { Ref map[string]*referencesShortcut // For internal library use only - SharedVariables map[string]*BPVariable - QFuncMain *Interface - QFuncInstance *bpFunction - QMainInstance *Instance - QRemote any + sharedVariables map[string]*BPVariable + _funcMain *Interface + _funcInstance *bpFunction + _mainInstance *Instance + _remote any } func New() *Instance { @@ -112,10 +112,10 @@ func (instance *Instance) ImportJSON(str []byte, options ...ImportOptions) (inse return } - return instance.ImportJSONParsed(data, options...) + return instance.importParsed(data, options...) } -func (instance *Instance) ImportJSONParsed(data singleInstanceJSON, options ...ImportOptions) (inserted []*Interface, err error) { +func (instance *Instance) importParsed(data singleInstanceJSON, options ...ImportOptions) (inserted []*Interface, err error) { hasOption := len(options) != 0 options_ := options[0] @@ -166,7 +166,7 @@ func (instance *Instance) ImportJSONParsed(data singleInstanceJSON, options ...I temp, inserted = instance.CreateNode(namespace, iface, inserted) ifaceList[iface.I] = temp - temp.QBpFnInit() + temp._bpFnInit() } } @@ -192,15 +192,15 @@ func (instance *Instance) ImportJSONParsed(data singleInstanceJSON, options ...I linkPortA := Output[portName] if linkPortA == nil { - if iface.QEnum == nodes.BPFnInput { - target := instance.QGetTargetPortType(iface.Node.Instance, "input", ports) + if iface._enum == nodes.BPFnInput { + target := instance._getTargetPortType(iface.Node.Instance, "input", ports) linkPortA = iface.Embed.(*qBpFnInOut).AddPort(target, portName) if linkPortA == nil { - panic(fmt.Sprintf("Can't create output port (%s) for function (%s)", portName, iface.QFuncMain.Node.QFuncInstance.Id)) + panic(fmt.Sprintf("Can't create output port (%s) for function (%s)", portName, iface._funcMain.Node._funcInstance.Id)) } - } else if iface.QEnum == nodes.BPVarGet { - target := instance.QGetTargetPortType(instance, "input", ports) + } else if iface._enum == nodes.BPVarGet { + target := instance._getTargetPortType(instance, "input", ports) iface.Embed.(*iVarGet).UseType(target) linkPortA = iface.Output[portName] } else { @@ -220,14 +220,14 @@ func (instance *Instance) ImportJSONParsed(data singleInstanceJSON, options ...I if linkPortB == nil { targetTitle := targetNode.Title - if targetNode.QEnum == nodes.BPFnOutput { + if targetNode._enum == nodes.BPFnOutput { linkPortB = targetNode.Embed.(*qBpFnInOut).AddPort(linkPortA, portName) if linkPortB == nil { - panic(fmt.Sprintf("Can't create output port (%s) for function (%s)", portName, targetNode.QFuncMain.Node.QFuncInstance.Id)) + panic(fmt.Sprintf("Can't create output port (%s) for function (%s)", portName, targetNode._funcMain.Node._funcInstance.Id)) } - } else if targetNode.QEnum == nodes.BPVarGet { - target := instance.QGetTargetPortType(instance, "input", ports) + } else if targetNode._enum == nodes.BPVarGet { + target := instance._getTargetPortType(instance, "input", ports) targetNode.Embed.(*iVarGet).UseType(target) linkPortB = targetNode.Input[target.Name] } else if linkPortA.Type == types.Route { @@ -260,7 +260,7 @@ func (instance *Instance) ImportJSONParsed(data singleInstanceJSON, options ...I } -func (instance *Instance) QGetTargetPortType(ins *Instance, which string, targetNodes []nodePortTarget) *Port { +func (instance *Instance) _getTargetPortType(ins *Instance, which string, targetNodes []nodePortTarget) *Port { target := targetNodes[0] // ToDo: check all target in case if it's supporting Union type targetIface := ins.IfaceList[target.I] @@ -308,7 +308,7 @@ func (instance *Instance) DeleteNode(iface *Interface) { delete(instance.Iface, iface.Id) delete(instance.Ref, iface.Id) - parent := iface.Node.Instance.QFuncInstance + parent := iface.Node.Instance._funcInstance if parent != nil { delete(parent.RootInstance.Ref, iface.Id) } @@ -394,7 +394,7 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes // *iface: extends engine.Interface iface := node.Iface - if iface == nil || iface.QInitialized == false { + if iface == nil || iface._initialized == false { panic(namespace + ": Node interface was not found, do you forget to call node.SetInterface() ?") } @@ -403,7 +403,7 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes // Create the linker between the nodes and the iface if isFuncNode == false { - iface.QPrepare(func_) + iface._prepare(func_) } if options.Id != "" { @@ -411,7 +411,7 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes instance.Iface[options.Id] = iface instance.Ref[options.Id] = iface.Ref - parent := iface.Node.QFuncInstance + parent := iface.Node._funcInstance if parent != nil { parent.RootInstance.Ref[options.Id] = iface.Ref } @@ -421,7 +421,7 @@ func (instance *Instance) CreateNode(namespace string, options nodeConfig, nodes instance.IfaceList[options.I] = iface if options.InputDefault != nil { - iface.QImportInputs(options.InputDefault) + iface._importInputs(options.InputDefault) } savedData := options.Data.(map[string]any) @@ -486,7 +486,7 @@ type funcOptions struct { Id string `json:"id"` Title string `json:"title"` Vars []string `json:"vars"` - PrivateVars []string `json:"privateVars"` + privateVars []string `json:"privateVars"` Structure singleInstanceJSON `json:"structure"` } @@ -527,25 +527,25 @@ func (instance *Instance) CreateFunction(id string, options any) *bpFunction { uniqId := 0 temp.Node = func(ins *Instance) *Node { - ins.QFuncInstance = temp + ins._funcInstance = temp node := &Node{ Instance: ins, - QFuncInstance: temp, + _funcInstance: temp, } node.Embed = &bpFunctionNode{} iface := node.SetInterface("BPIC/BP/Fn/Main") iface.Embed.(*bpFunctionNode).Type = "function" - iface.QEnum = nodes.BPFnMain + iface._enum = nodes.BPFnMain iface.Namespace = id iface.Title = title uniqId += 1 iface.uniqId = uniqId - iface.QPrepare(meta) + iface._prepare(meta) return node } @@ -557,7 +557,7 @@ func (instance *Instance) CreateFunction(id string, options any) *bpFunction { }) } - for _, val := range options_.PrivateVars { + for _, val := range options_.privateVars { temp.AddPrivateVars(val) } @@ -572,7 +572,7 @@ type NodeLogEvent struct { Message string } -func (instance *Instance) QLog(iface *Interface, message string) { +func (instance *Instance) _log(iface *Interface, message string) { evData := NodeLogEvent{ Instance: instance, Iface: iface, @@ -580,8 +580,8 @@ func (instance *Instance) QLog(iface *Interface, message string) { Message: message, } - if instance.QMainInstance != nil { - instance.QMainInstance.Emit("log", evData) + if instance._mainInstance != nil { + instance._mainInstance.Emit("log", evData) } else { instance.Emit("log", evData) } diff --git a/engine/environment.go b/engine/environment.go index f6d68a4..aee2642 100644 --- a/engine/environment.go +++ b/engine/environment.go @@ -3,7 +3,7 @@ package engine import "regexp" type environment struct { - QNoEvent bool + _noEvent bool Map map[string]string } @@ -13,11 +13,11 @@ var QEnvironment = &environment{ // arr = ["KEY": "value"] func (e *environment) Import(arr map[string]string) { - e.QNoEvent = true + e._noEvent = true for key, val := range arr { e.Set(key, val) } - e.QNoEvent = false + e._noEvent = false Event.Emit("environment.imported", nil) } @@ -35,7 +35,7 @@ func (e *environment) Set(key string, val string) { e.Map[key] = val - if !e.QNoEvent { + if !e._noEvent { Event.Emit("environment.added", &EnvironmentEvent{ Key: key, Value: val, diff --git a/engine/interface.go b/engine/interface.go index f02c8d9..d12ea4b 100644 --- a/engine/interface.go +++ b/engine/interface.go @@ -53,17 +53,17 @@ type Interface struct { Importing bool // for internal library use only - QInitialized bool - QRequesting bool - QFuncMain *Interface - QDynamicPort bool - QEnum int - QBpVarRef *BPVariable - QProxyInput *Node - QProxyOutput *Node - QParentFunc *Interface - QBpInstance *Instance - QBpDestroy bool + _initialized bool + _requesting bool + _funcMain *Interface + _dynamicPort bool + _enum int + _bpVarRef *BPVariable + _proxyInput *Node + _proxyOutput *Node + _parentFunc *Interface + _bpInstance *Instance + _bpDestroy bool } // To be overriden @@ -72,12 +72,12 @@ func (i *Interface) Destroy() { i.Embed.Destroy() } func (i *Interface) Imported(data map[string]any) { i.Embed.Imported(data) } // Internal blackprint function node initialization -func (iface *Interface) QBpFnInit() {} +func (iface *Interface) _bpFnInit() {} var reflectKind = reflect.TypeOf(reflect.Int) // Private (to be called for internal library only) -func (iface *Interface) QPrepare(meta *NodeRegister) { +func (iface *Interface) _prepare(meta *NodeRegister) { iface.CustomEvent = &CustomEvent{} ref := &referencesShortcut{} @@ -118,7 +118,7 @@ func (iface *Interface) QPrepare(meta *NodeRegister) { // name: string for name, config_ := range port { - linkedPort := iface.QCreatePort(which, name, config_) + linkedPort := iface._createPort(which, name, config_) ifacePort[name] = linkedPort // CreateLinker() @@ -131,7 +131,7 @@ func (iface *Interface) QPrepare(meta *NodeRegister) { } } -func (iface *Interface) QCreatePort(which string, name string, config_ any) *Port { +func (iface *Interface) _createPort(which string, name string, config_ any) *Port { var config *portFeature var type_ reflect.Kind var types_ []reflect.Kind @@ -195,17 +195,17 @@ func (iface *Interface) QCreatePort(which string, name string, config_ any) *Por Type: type_, Types: types_, Default: def, - QFunc: qfunc, + _func: qfunc, Source: source, Iface: iface, Feature: feature, - QFeature: config, + _feature: config, } return port } -func (iface *Interface) QInitPortSwitches(portSwitches map[string]int) { +func (iface *Interface) _initPortSwitches(portSwitches map[string]int) { for key, val := range portSwitches { if (val | 1) == 1 { portStructOf_split(iface.Output[key]) @@ -218,7 +218,7 @@ func (iface *Interface) QInitPortSwitches(portSwitches map[string]int) { } // Load saved port data value -func (iface *Interface) QImportInputs(ports map[string]any) { +func (iface *Interface) _importInputs(ports map[string]any) { for key, val := range ports { iface.Input[key].Default = val } diff --git a/engine/node.go b/engine/node.go index c73b44d..fe0a082 100644 --- a/engine/node.go +++ b/engine/node.go @@ -42,7 +42,7 @@ type Node struct { // Property map[string]getterSetter // For internal library use only - QFuncInstance *bpFunction + _funcInstance *bpFunction RefOutput map[string]*portOutputGetterSetter // RefInput map[string]*portInputGetterSetter } @@ -78,7 +78,7 @@ var QNodeList = map[string]*NodeRegister{} var QInterfaceList = map[string]*InterfaceRegister{} func (n *Node) SetInterface(namespace ...string) *Interface { - iface := &Interface{QInitialized: true, Importing: true} + iface := &Interface{_initialized: true, Importing: true} // Default interface (BP/Default) if len(namespace) == 0 { @@ -97,7 +97,7 @@ func (n *Node) SetInterface(namespace ...string) *Interface { utils.SetProperty(val, "Iface", iface) } - iface.QInitialized = true + iface._initialized = true iface.Importing = true n.Iface = iface @@ -105,7 +105,7 @@ func (n *Node) SetInterface(namespace ...string) *Interface { } func (n *Node) CreatePort(which string, name string, config_ any) *Port { - port := n.Iface.QCreatePort(which, name, config_) + port := n.Iface._createPort(which, name, config_) if which != "input" { ifacePort := n.Iface.Input @@ -184,5 +184,5 @@ func (n *Node) DeletePort(which string, name string) { } func (n *Node) Log(message string) { - n.Instance.QLog(n.Iface, message) + n.Instance._log(n.Iface, message) } diff --git a/engine/nodesBPFunction.go b/engine/nodesBPFunction.go index fca8fb6..2dfee96 100644 --- a/engine/nodesBPFunction.go +++ b/engine/nodesBPFunction.go @@ -17,18 +17,18 @@ type bpFunctionNode struct { // Main function node -> BPI/F/{FunctionName} } func (b *bpFunctionNode) Init() { - if b.Iface.Embed.(*FnMain).QImportOnce { - b.Iface.QBpFnInit() + if b.Iface.Embed.(*FnMain)._importOnce { + b.Iface._bpFnInit() } } func (b *bpFunctionNode) Imported(data map[string]any) { - ins := b.Node.QFuncInstance + ins := b.Node._funcInstance ins.Used = append(ins.Used, b.Node.Iface) } func (b *bpFunctionNode) Update(cable *Cable) { - iface := b.Iface.QProxyInput.Iface + iface := b.Iface._proxyInput.Iface Output := iface.Node.Output if cable == nil { // Triggered by port route @@ -51,7 +51,7 @@ func (b *bpFunctionNode) Update(cable *Cable) { } func (b *bpFunctionNode) Destroy() { - ins := b.Node.QFuncInstance + ins := b.Node._funcInstance utils.RemoveItem(ins.Used, b.Node.Iface) } @@ -66,31 +66,31 @@ type bpFunction struct { // <= _funcInstance Output PortTemplate Structure singleInstanceJSON Variables map[string]*BPVariable - PrivateVars []string + privateVars []string RootInstance *Instance Node func(*Instance) *Node // Node constructor // for internal library use only - QSyncing bool + _syncing bool } -func (b *bpFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { +func (b *bpFunction) _onFuncChanges(eventName string, obj any, fromNode *Node) { for _, iface_ := range b.Used { if iface_.Node == fromNode { continue } - nodeInstance := iface_.QBpInstance + nodeInstance := iface_._bpInstance // nodeInstance.PendingRender = true // Force recalculation for cable position if eventName == "cable.connect" || eventName == "cable.disconnect" { cable := utils.GetProperty(obj, "Cable").(*Cable) input := cable.Input output := cable.Output - ifaceList := fromNode.Iface.QBpInstance.IfaceList + ifaceList := fromNode.Iface._bpInstance.IfaceList // Skip event that also triggered when deleting a node - if input.Iface.QBpDestroy || output.Iface.QBpDestroy { + if input.Iface._bpDestroy || output.Iface._bpDestroy { continue } @@ -119,7 +119,7 @@ func (b *bpFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { targetOutput := outputIface.Output[output.Name] if targetInput == nil { - if inputIface.QEnum == nodes.BPFnOutput { + if inputIface._enum == nodes.BPFnOutput { targetInput = inputIface.Embed.(*qBpFnInOut).AddPort(targetOutput, output.Name) } else { panic("Output port was not found") @@ -127,7 +127,7 @@ func (b *bpFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { } if targetOutput == nil { - if outputIface.QEnum == nodes.BPFnInput { + if outputIface._enum == nodes.BPFnInput { targetOutput = outputIface.Embed.(*qBpFnInOut).AddPort(targetInput, input.Name) } else { panic("Input port was not found") @@ -154,7 +154,7 @@ func (b *bpFunction) QOnFuncChanges(eventName string, obj any, fromNode *Node) { } else if eventName == "node.delete" { objIface := utils.GetProperty(obj, "Iface").(*Interface) - index := utils.IndexOf(fromNode.Iface.QBpInstance.IfaceList, objIface) + index := utils.IndexOf(fromNode.Iface._bpInstance.IfaceList, objIface) if index == -1 { panic("Failed to get node index") } @@ -211,11 +211,11 @@ type VariableNewEvent struct { } func (b *bpFunction) AddPrivateVars(id string) { - if utils.Contains(b.PrivateVars, id) { + if utils.Contains(b.privateVars, id) { return } - b.PrivateVars = append(b.PrivateVars, id) + b.privateVars = append(b.privateVars, id) temp := &VariableNewEvent{ ScopeId: VarScopePrivate, @@ -225,13 +225,13 @@ func (b *bpFunction) AddPrivateVars(id string) { b.RootInstance.Emit("variable.new", temp) for _, iface := range b.Used { - iface.QBpInstance.Variables[id] = &BPVariable{Id: id} + iface._bpInstance.Variables[id] = &BPVariable{Id: id} } } func (b *bpFunction) RefreshPrivateVars(instance *Instance) { vars := instance.Variables - for _, id := range b.PrivateVars { + for _, id := range b.privateVars { vars[id] = &BPVariable{Id: id} } } @@ -255,16 +255,16 @@ func (b *bpFunction) RenamePort(which string, fromName string, toName string) { var temp *Node if which == "output" { - temp = iface.QProxyOutput + temp = iface._proxyOutput } else { - temp = iface.QProxyInput + temp = iface._proxyInput } portList := utils.GetProperty(temp.Iface, proxyPort).(map[string]*Port) portList[fromName].Name_.Name = toName temp.RenamePort(proxyPort, fromName, toName) - for _, proxyVar := range iface.QBpInstance.IfaceList { + for _, proxyVar := range iface._bpInstance.IfaceList { if (which == "output" && proxyVar.Namespace != "BP/FnVar/Output") || (which == "input" && proxyVar.Namespace != "BP/FnVar/Input") { continue } @@ -292,7 +292,7 @@ type qNodeInput struct { } func (n *qNodeInput) Imported(data map[string]any) { - input := n.Iface.QFuncMain.Node.QFuncInstance.Input + input := n.Iface._funcMain.Node._funcInstance.Input for key, value := range input { n.Node.CreatePort("output", key, value) @@ -303,7 +303,7 @@ func (n *qNodeInput) Request(cable *Cable) { name := cable.Output.Name // This will trigger the port to request from outside and assign to this node's port - n.Node.Output[name].Set(n.Iface.QFuncMain.Node.Input[name].Get()) + n.Node.Output[name].Set(n.Iface._funcMain.Node.Input[name].Get()) } type qNodeOutput struct { @@ -311,7 +311,7 @@ type qNodeOutput struct { } func (n *qNodeOutput) Imported(data map[string]any) { - output := n.Iface.QFuncMain.Node.QFuncInstance.Output + output := n.Iface._funcMain.Node._funcInstance.Output for key, value := range output { n.Node.CreatePort("input", key, value) @@ -319,7 +319,7 @@ func (n *qNodeOutput) Imported(data map[string]any) { } func (n *qNodeOutput) Update(cable *Cable) { - iface := n.Iface.QFuncMain + iface := n.Iface._funcMain if cable == nil { // Triggered by port route IOutput := iface.Output Output := iface.Node.Output @@ -341,74 +341,74 @@ func (n *qNodeOutput) Update(cable *Cable) { type FnMain struct { *EmbedInterface - QImportOnce bool - QSave func(any, string, bool) - QPortSw_ map[string]int + _importOnce bool + _save func(any, string, bool) + _portSw_ map[string]int } -func (f *FnMain) QBpFnInit() { - if f.QImportOnce { +func (f *FnMain) _bpFnInit() { + if f._importOnce { panic("Can't import function more than once") } - f.QImportOnce = true + f._importOnce = true node := f.Node - f.Iface.QBpInstance = New() - bpFunction := node.QFuncInstance + f.Iface._bpInstance = New() + bpFunction := node._funcInstance - newInstance := f.Iface.QBpInstance + newInstance := f.Iface._bpInstance // newInstance.Variables = []; // private for one function - newInstance.SharedVariables = bpFunction.Variables // shared between function + newInstance.sharedVariables = bpFunction.Variables // shared between function newInstance.Functions = node.Instance.Functions - newInstance.QFuncMain = f.Iface - newInstance.QMainInstance = bpFunction.RootInstance + newInstance._funcMain = f.Iface + newInstance._mainInstance = bpFunction.RootInstance bpFunction.RefreshPrivateVars(newInstance) // swallowCopy := make([]any, len(bpFunction.Structure)) // copy(swallowCopy, bpFunction.Structure) - f.Iface.QBpInstance.ImportJSONParsed(bpFunction.Structure) + f.Iface._bpInstance.importParsed(bpFunction.Structure) // Init port switches - if f.QPortSw_ != nil { - f.Iface.QInitPortSwitches(f.QPortSw_) - f.QPortSw_ = nil + if f._portSw_ != nil { + f.Iface._initPortSwitches(f._portSw_) + f._portSw_ = nil - InputIface := f.Iface.QProxyInput.Iface + InputIface := f.Iface._proxyInput.Iface InputIface_ := InputIface.Embed.(*qBpFnInOut) - if InputIface_.QPortSw_ != nil { - InputIface.QInitPortSwitches(InputIface_.QPortSw_) - InputIface_.QPortSw_ = nil + if InputIface_._portSw_ != nil { + InputIface._initPortSwitches(InputIface_._portSw_) + InputIface_._portSw_ = nil } } - f.QSave = func(ev any, eventName string, force bool) { - if force || bpFunction.QSyncing { + f._save = func(ev any, eventName string, force bool) { + if force || bpFunction._syncing { return } // ev.BpFunction = bpFunction - newInstance.QMainInstance.Emit(eventName, ev) + newInstance._mainInstance.Emit(eventName, ev) - bpFunction.QSyncing = true - bpFunction.QOnFuncChanges(eventName, ev, f.Node) - bpFunction.QSyncing = false + bpFunction._syncing = true + bpFunction._onFuncChanges(eventName, ev, f.Node) + bpFunction._syncing = false } - f.Iface.QBpInstance.On("cable.connect cable.disconnect node.created node.delete node.id.changed", f.QSave) + f.Iface._bpInstance.On("cable.connect cable.disconnect node.created node.delete node.id.changed", f._save) } func (f *FnMain) RenamePort(which string, fromName string, toName string) { - f.Node.QFuncInstance.RenamePort(which, fromName, toName) - f.QSave(false, "", true) + f.Node._funcInstance.RenamePort(which, fromName, toName) + f._save(false, "", true) } type qBpFnInOut struct { *EmbedInterface Type string - QPortSw_ map[string]int + _portSw_ map[string]int } type addPortRef struct { @@ -443,7 +443,7 @@ func (b *qBpFnInOut) AddPort(port *Port, customName string) *Port { }) } else { if port.Feature != 0 { - portType = port.QGetPortFeature() + portType = port._getPortFeature() } else { portType = port.Type } @@ -464,9 +464,9 @@ func (b *qBpFnInOut) AddPort(port *Port, customName string) *Port { inc++ } - nodeA = b.Iface.QFuncMain.Node + nodeA = b.Iface._funcMain.Node nodeB = b.Node - nodeA.QFuncInstance.Input[name] = portType + nodeA._funcInstance.Input[name] = portType } else { // Output (input) -> Main (output) inc := 1 for true { @@ -480,15 +480,15 @@ func (b *qBpFnInOut) AddPort(port *Port, customName string) *Port { } nodeA = b.Node - nodeB = b.Iface.QFuncMain.Node - nodeB.QFuncInstance.Output[name] = portType + nodeB = b.Iface._funcMain.Node + nodeB._funcInstance.Output[name] = portType } outputPort := nodeB.CreatePort("output", name, portType) var inputPort *Port if portType == types.Function { - inputPort = nodeA.CreatePort("input", name, QPorts.Trigger(outputPort.QCallAll)) + inputPort = nodeA.CreatePort("input", name, QPorts.Trigger(outputPort._callAll)) } else { inputPort = nodeA.CreatePort("input", name, portType) } @@ -515,7 +515,7 @@ func (b *qBpFnInOut) AddPort(port *Port, customName string) *Port { } func (b *qBpFnInOut) RenamePort(fromName string, toName string) { - bpFunction := b.Iface.QFuncMain.Node.QFuncInstance + bpFunction := b.Iface._funcMain.Node._funcInstance // Main (input) -> Input (output) if b.Type == "bp-fn-input" { bpFunction.RenamePort("input", fromName, toName) @@ -525,15 +525,15 @@ func (b *qBpFnInOut) RenamePort(fromName string, toName string) { } func (b *qBpFnInOut) DeletePort(name string) { - funcMainNode := b.Iface.QFuncMain.Node + funcMainNode := b.Iface._funcMain.Node if b.Type == "bp-fn-input" { // Main (input) -> Input (output) funcMainNode.DeletePort("input", name) b.Node.DeletePort("output", name) - delete(funcMainNode.QFuncInstance.Input, name) + delete(funcMainNode._funcInstance.Input, name) } else { // Output (input) -> Main (output) funcMainNode.DeletePort("output", name) b.Node.DeletePort("input", name) - delete(funcMainNode.QFuncInstance.Output, name) + delete(funcMainNode._funcInstance.Output, name) } } @@ -544,13 +544,13 @@ func init() { node.Embed = &qNodeInput{} iface := node.SetInterface("BPIC/BP/Fn/Input") - iface.QEnum = nodes.BPFnInput - iface.QDynamicPort = true // Port is initialized dynamically + iface._enum = nodes.BPFnInput + iface._dynamicPort = true // Port is initialized dynamically iface.Title = "Input" iface.Embed.(*qBpFnInOut).Type = "bp-fn-input" - iface.QFuncMain = node.Instance.QFuncMain - iface.QFuncMain.QProxyInput = node + iface._funcMain = node.Instance._funcMain + iface._funcMain._proxyInput = node }, } @@ -566,13 +566,13 @@ func init() { node.Embed = &bpVarGet{} iface := node.SetInterface("BPIC/BP/Fn/Output") - iface.QEnum = nodes.BPFnOutput - iface.QDynamicPort = true // Port is initialized dynamically + iface._enum = nodes.BPFnOutput + iface._dynamicPort = true // Port is initialized dynamically iface.Title = "Output" iface.Embed.(*qBpFnInOut).Type = "bp-fn-output" - iface.QFuncMain = node.Instance.QFuncMain - iface.QFuncMain.QProxyOutput = node + iface._funcMain = node.Instance._funcMain + iface._funcMain._proxyOutput = node }, } diff --git a/engine/nodesBPVariable.go b/engine/nodesBPVariable.go index 50f8143..773f747 100644 --- a/engine/nodesBPVariable.go +++ b/engine/nodesBPVariable.go @@ -16,19 +16,19 @@ type bpVarGet struct { } func (b *bpVarSet) Update(c *Cable) { - b.Iface.QBpVarRef.Value.Set(b.Node.Input["Val"].Get()) + b.Iface._bpVarRef.Value.Set(b.Node.Input["Val"].Get()) } type bpVarGetSet struct { *EmbedInterface bpVarGetSetIFace Type string - QBpVarRef *BPVariable - QOnChanged func(*Port) + _bpVarRef *BPVariable + _onChanged func(*Port) } type bpVarGetSetIFace interface { - QReinitPort() *Port + _reinitPort() *Port } func (b *bpVarGetSet) Imported(data map[string]any) { @@ -41,7 +41,7 @@ func (b *bpVarGetSet) Imported(data map[string]any) { } b.ChangeVar(data["name"].(string), data["scope"].(int)) - b.QBpVarRef.Used = append(b.QBpVarRef.Used, b.Iface) + b._bpVarRef.Used = append(b._bpVarRef.Used, b.Iface) } func (b *bpVarGetSet) ChangeVar(name string, scopeId int) map[string]*BPVariable { @@ -53,10 +53,10 @@ func (b *bpVarGetSet) ChangeVar(name string, scopeId int) map[string]*BPVariable b.Iface.Data["scope"] = &GetterSetter{Value: scopeId} thisInstance := b.Node.Instance - funcInstance := thisInstance.QFuncMain + funcInstance := thisInstance._funcMain var bpFunc *bpFunction if funcInstance != nil { - bpFunc = funcInstance.Node.QFuncInstance + bpFunc = funcInstance.Node._funcInstance } var scope map[string]*BPVariable @@ -91,9 +91,9 @@ func (b *bpVarGetSet) ChangeVar(name string, scopeId int) map[string]*BPVariable } func (b *bpVarGetSet) UseType(port *Port) bool { - if b.QBpVarRef.Type != 0 { // Type was set + if b._bpVarRef.Type != 0 { // Type was set if port == nil { - b.QBpVarRef.Type = 0 // Type not set + b._bpVarRef.Type = 0 // Type not set } return true } @@ -106,39 +106,39 @@ func (b *bpVarGetSet) UseType(port *Port) bool { } func (b *bpVarGetSet) UseType_(port *Port, targetPort *Port) { - b.QBpVarRef.Type = port.Type + b._bpVarRef.Type = port.Type targetPort.ConnectPort(port) // Also create port for other node that using $this variable - for _, item := range b.QBpVarRef.Used { - item.Embed.(bpVarGetSetIFace).QReinitPort() + for _, item := range b._bpVarRef.Used { + item.Embed.(bpVarGetSetIFace)._reinitPort() } } func (b *bpVarGetSet) Destroy() { - temp := b.QBpVarRef + temp := b._bpVarRef if temp == nil { return } temp.Used = utils.RemoveItem(temp.Used, b.Iface) - listener := b.QBpVarRef.Listener + listener := b._bpVarRef.Listener if listener == nil { return } - b.QBpVarRef.Listener = utils.RemoveItem(listener, b.Iface) + b._bpVarRef.Listener = utils.RemoveItem(listener, b.Iface) } type iVarSet struct { *bpVarGetSet - QEventListen string + _eventListen string } func (b *iVarSet) UseType(port *Port) { if !b.bpVarGetSet.UseType(port) { - b.bpVarGetSet.UseType_(port, b.QReinitPort()) + b.bpVarGetSet.UseType_(port, b._reinitPort()) } } @@ -147,24 +147,24 @@ func (b *iVarSet) ChangeVar(name string, scopeId int) { panic("Can't change variable node that already be initialized") } - if b.QOnChanged != nil && b.QBpVarRef != nil { - b.QBpVarRef.Off("value", b.QOnChanged) + if b._onChanged != nil && b._bpVarRef != nil { + b._bpVarRef.Off("value", b._onChanged) } scope := b.bpVarGetSet.ChangeVar(name, scopeId) b.Iface.Title = "Get " + name temp := scope[b.Iface.Data["name"].Get().(string)] - b.QBpVarRef = temp + b._bpVarRef = temp if temp.Type == 0 { // Type not set return } - b.QReinitPort() + b._reinitPort() } -func (b *iVarSet) QReinitPort() *Port { - temp := b.QBpVarRef +func (b *iVarSet) _reinitPort() *Port { + temp := b._bpVarRef node := b.Node if b.Iface.Output["Val"] != nil { @@ -175,24 +175,24 @@ func (b *iVarSet) QReinitPort() *Port { b.Node.CreatePort("output", "Val", temp.Type) if temp.Type == types.Function { - b.QEventListen = "call" - b.QOnChanged = func(p *Port) { + b._eventListen = "call" + b._onChanged = func(p *Port) { ref["Val"].Call() } } else { - b.QEventListen = "value" - b.QOnChanged = func(p *Port) { + b._eventListen = "value" + b._onChanged = func(p *Port) { ref["Val"].Set(temp.Value.Get()) } } - temp.On(b.QEventListen, b.QOnChanged) + temp.On(b._eventListen, b._onChanged) return b.Iface.Output["Val"] } func (b *iVarSet) Destroy() { - if b.QEventListen != "" { - b.QBpVarRef.Off(b.QEventListen, b.QOnChanged) + if b._eventListen != "" { + b._bpVarRef.Off(b._eventListen, b._onChanged) } b.bpVarGetSet.Destroy() @@ -204,7 +204,7 @@ type iVarGet struct { func (b *iVarGet) UseType(port *Port) { if !b.bpVarGetSet.UseType(port) { - b.bpVarGetSet.UseType_(port, b.QReinitPort()) + b.bpVarGetSet.UseType_(port, b._reinitPort()) } } @@ -213,18 +213,18 @@ func (b *iVarGet) ChangeVar(name string, scopeId int) { b.Iface.Title = "Set " + name temp := scope[b.Iface.Data["name"].Get().(string)] - b.QBpVarRef = temp + b._bpVarRef = temp if temp.Type == 0 { // Type not set return } - b.QReinitPort() + b._reinitPort() } -func (b *iVarGet) QReinitPort() *Port { +func (b *iVarGet) _reinitPort() *Port { input := b.Iface.Input node := b.Node - temp := b.QBpVarRef + temp := b._bpVarRef if _, exist := input["Val"]; exist { node.DeletePort("Input", "Val") @@ -257,8 +257,8 @@ func init() { iface.Title = "VarSet" iface.Embed.(*iVarSet).Type = "bp-var-set" - iface.QEnum = nodes.BPVarSet - iface.QDynamicPort = true + iface._enum = nodes.BPVarSet + iface._dynamicPort = true }, } @@ -285,8 +285,8 @@ func init() { iface.Title = "VarGet" iface.Embed.(*iVarGet).Type = "bp-var-get" - iface.QEnum = nodes.BPVarGet - iface.QDynamicPort = true + iface._enum = nodes.BPVarGet + iface._dynamicPort = true }, } diff --git a/engine/nodesEnvironment.go b/engine/nodesEnvironment.go index 23497c3..e06c3b6 100644 --- a/engine/nodesEnvironment.go +++ b/engine/nodesEnvironment.go @@ -37,13 +37,13 @@ func (b *bpEnvGetSet) Imported(data map[string]any) { type iEnvGet struct { *bpEnvGetSet - QListener func(any) + _listener func(any) } func (b *iEnvGet) Imported(data map[string]any) { b.bpEnvGetSet.Imported(data) - b.QListener = func(v any) { + b._listener = func(v any) { ev := v.(*EnvironmentEvent) if ev.Key != b.Iface.Data["name"].Get().(string) { return @@ -52,16 +52,16 @@ func (b *iEnvGet) Imported(data map[string]any) { b.Ref.Output["Val"].Set(ev.Value) } - Event.On("environment.changed environment.added", b.QListener) + Event.On("environment.changed environment.added", b._listener) b.Ref.Output["Val"].Set(QEnvironment.Map[b.Iface.Data["name"].Get().(string)]) } func (b *iEnvGet) Destroy() { - if b.QListener == nil { + if b._listener == nil { return } - Event.Off("environment.changed environment.added", b.QListener) + Event.Off("environment.changed environment.added", b._listener) } type iEnvSet struct { @@ -85,7 +85,7 @@ func init() { iface.Title = "EnvGet" iface.Embed.(*iEnvGet).Type = "bp-env-get" - iface.QEnum = nodes.BPEnvGet + iface._enum = nodes.BPEnvGet }, } @@ -113,7 +113,7 @@ func init() { iface.Title = "EnvSet" iface.Embed.(*iEnvSet).Type = "bp-env-set" - iface.QEnum = nodes.BPEnvSet + iface._enum = nodes.BPEnvSet }, } diff --git a/engine/nodesFnPortVar.go b/engine/nodesFnPortVar.go index 02f3382..22a1943 100644 --- a/engine/nodesFnPortVar.go +++ b/engine/nodesFnPortVar.go @@ -19,7 +19,7 @@ func (f *fnVarInput) Request(cable *Cable) { iface := f.Iface // This will trigger the port to request from outside and assign to this node's port - f.Node.Output["Val"].Set(iface.QParentFunc.Node.Input[iface.Data["name"].Get().(string)]) + f.Node.Output["Val"].Set(iface._parentFunc.Node.Input[iface.Data["name"].Get().(string)]) } type fnVarOutput struct { @@ -33,12 +33,12 @@ func (f *fnVarOutput) Update(c *Cable) { type bpFnVarInOut struct { *EmbedInterface - QOnConnect func(*Cable, *Port) + _onConnect func(*Cable, *Port) - QParentFunc *Interface - QProxyIface *Interface - QListener func(any) - QWaitPortInit func(*Port) + _parentFunc *Interface + _proxyIface *Interface + _listener func(any) + _waitPortInit func(*Port) Type string } @@ -48,7 +48,7 @@ func (f *bpFnVarInOut) Imported(data map[string]any) { } f.Iface.Data["name"].Set(data["name"]) - f.QParentFunc = f.Node.Instance.QFuncMain + f._parentFunc = f.Node.Instance._funcMain } type fnVarInputIface struct { @@ -57,42 +57,42 @@ type fnVarInputIface struct { func (f *fnVarInputIface) Imported(data map[string]any) { f.bpFnVarInOut.Imported(data) - ports := f.QParentFunc.Ref.IInput + ports := f._parentFunc.Ref.IInput node := f.Node - f.QProxyIface = f.QParentFunc.QProxyInput.Iface + f._proxyIface = f._parentFunc._proxyInput.Iface // Create temporary port if the main function doesn't have the port name := data["name"].(string) if _, exist := ports[name]; !exist { iPort := node.CreatePort("input", "Val", types.Any) - proxyIface := f.QProxyIface + proxyIface := f._proxyIface // Run when $this node is being connected with other node - iPort.QOnConnect = func(cable *Cable, port *Port) bool { - iPort.QOnConnect = nil - proxyIface.Off("_add."+name, iPort.QWaitPortInit) - iPort.QWaitPortInit = nil + iPort._onConnect = func(cable *Cable, port *Port) bool { + iPort._onConnect = nil + proxyIface.Off("_add."+name, iPort._waitPortInit) + iPort._waitPortInit = nil cable.Disconnect() node.DeletePort("output", "Val") portName := &refPortName{Name: name} - portType := getFnPortType(port, "input", f.QParentFunc, portName) + portType := getFnPortType(port, "input", f._parentFunc, portName) newPort := node.CreatePort("output", "Val", portType) newPort.Name_ = portName newPort.ConnectPort(port) proxyIface.Embed.(*qBpFnInOut).AddPort(port, name) - f.QAddListener() + f._addListener() return true } // Run when main node is the missing port - iPort.QWaitPortInit = func(port *Port) { - iPort.QOnConnect = nil - iPort.QWaitPortInit = nil + iPort._waitPortInit = func(port *Port) { + iPort._onConnect = nil + iPort._waitPortInit = nil backup := []*Port{} for _, val := range f.Iface.Output["Val"].Cables { @@ -102,38 +102,38 @@ func (f *fnVarInputIface) Imported(data map[string]any) { node := f.Node node.DeletePort("output", "Val") - portType := getFnPortType(port, "input", f.QParentFunc, port.Name_) + portType := getFnPortType(port, "input", f._parentFunc, port.Name_) newPort := node.CreatePort("output", "Val", portType) - f.QAddListener() + f._addListener() for _, val := range backup { newPort.ConnectPort(val) } } - proxyIface.Once("_add."+name, iPort.QWaitPortInit) + proxyIface.Once("_add."+name, iPort._waitPortInit) } else { if _, exist := f.Iface.Output["Val"]; !exist { port := ports[name] - portType := getFnPortType(port, "input", f.QParentFunc, port.Name_) + portType := getFnPortType(port, "input", f._parentFunc, port.Name_) node.CreatePort("input", "Val", portType) } - f.QAddListener() + f._addListener() } } -func (f *fnVarInputIface) QAddListener() { - port := f.QProxyIface.Output[f.Iface.Data["name"].Get().(string)] +func (f *fnVarInputIface) _addListener() { + port := f._proxyIface.Output[f.Iface.Data["name"].Get().(string)] if port.Feature == PortTypeTrigger { - f.QListener = func(p any) { + f._listener = func(p any) { f.Ref.Output["Val"].Call() } - port.On("call", f.QListener) + port.On("call", f._listener) } else { - f.QListener = func(ev any) { + f._listener = func(ev any) { port := ev.(*PortValueEvent).Port if port.Iface.Node.Routes.Out == nil { val := f.Ref.IOutput["Val"] @@ -141,7 +141,7 @@ func (f *fnVarInputIface) QAddListener() { for _, temp := range val.Cables { // Clear connected cable's cache - temp.Input.QCache = nil + temp.Input._cache = nil } return } @@ -149,22 +149,22 @@ func (f *fnVarInputIface) QAddListener() { f.Ref.Output["Val"].Set(port.Value) } - port.On("value", f.QListener) + port.On("value", f._listener) } } func (f *fnVarInputIface) Destroy() { f.bpFnVarInOut.Destroy() - if f.QListener == nil { + if f._listener == nil { return } - port := f.QProxyIface.Output[f.Iface.Data["name"].Get().(string)] + port := f._proxyIface.Output[f.Iface.Data["name"].Get().(string)] if port.Feature == PortTypeTrigger { - port.Off("call", f.QListener) + port.Off("call", f._listener) } else { - port.Off("value", f.QListener) + port.Off("value", f._listener) } } @@ -174,28 +174,28 @@ type fnVarOutputIface struct { func (f *fnVarOutputIface) Imported(data map[string]any) { f.bpFnVarInOut.Imported(data) - ports := f.QParentFunc.Ref.IOutput + ports := f._parentFunc.Ref.IOutput node := f.Node - node.RefOutput = f.QParentFunc.Ref.Output + node.RefOutput = f._parentFunc.Ref.Output // Create temporary port if the main function doesn't have the port name := data["name"].(string) if _, exist := ports[name]; !exist { iPort := node.CreatePort("input", "Val", types.Any) - proxyIface := f.QParentFunc.QProxyOutput.Iface + proxyIface := f._parentFunc._proxyOutput.Iface // Run when $this node is being connected with other node - iPort.QOnConnect = func(cable *Cable, port *Port) bool { - iPort.QOnConnect = nil - proxyIface.Off("_add."+name, iPort.QWaitPortInit) - iPort.QWaitPortInit = nil + iPort._onConnect = func(cable *Cable, port *Port) bool { + iPort._onConnect = nil + proxyIface.Off("_add."+name, iPort._waitPortInit) + iPort._waitPortInit = nil cable.Disconnect() node.DeletePort("input", "Val") portName := &refPortName{Name: name} - portType := getFnPortType(port, "output", f.QParentFunc, portName) + portType := getFnPortType(port, "output", f._parentFunc, portName) newPort := node.CreatePort("input", "Val", portType) newPort.Name_ = portName newPort.ConnectPort(port) @@ -205,9 +205,9 @@ func (f *fnVarOutputIface) Imported(data map[string]any) { } // Run when main node is the missing port - iPort.QWaitPortInit = func(port *Port) { - iPort.QOnConnect = nil - iPort.QWaitPortInit = nil + iPort._waitPortInit = func(port *Port) { + iPort._onConnect = nil + iPort._waitPortInit = nil backup := []*Port{} for _, val := range f.Iface.Output["Val"].Cables { @@ -217,7 +217,7 @@ func (f *fnVarOutputIface) Imported(data map[string]any) { node := f.Node node.DeletePort("input", "Val") - portType := getFnPortType(port, "output", f.QParentFunc, port.Name_) + portType := getFnPortType(port, "output", f._parentFunc, port.Name_) newPort := node.CreatePort("input", "Val", portType) for _, val := range backup { @@ -225,11 +225,11 @@ func (f *fnVarOutputIface) Imported(data map[string]any) { } } - proxyIface.Once("_add."+name, iPort.QWaitPortInit) + proxyIface.Once("_add."+name, iPort._waitPortInit) } else { if _, exist := f.Iface.Output["Val"]; !exist { port := ports[name] - portType := getFnPortType(port, "output", f.QParentFunc, port.Name_) + portType := getFnPortType(port, "output", f._parentFunc, port.Name_) node.CreatePort("input", "Val", portType) } } @@ -240,11 +240,11 @@ func getFnPortType(port *Port, which string, parentNode *Interface, ref *refPort if which == "input" { // Function Input (has output port inside, and input port on main node) return types.Function } else { - return QPorts.Trigger(parentNode.Output[ref.Name].QCallAll) + return QPorts.Trigger(parentNode.Output[ref.Name]._callAll) } } else { if port.Feature != 0 { - return port.QGetPortFeature() + return port._getPortFeature() } else { return port.Type } @@ -266,8 +266,8 @@ func init() { iface.Title = "FnInput" iface.Embed.(*fnVarInputIface).Type = "bp-fnvar-input" - iface.QEnum = nodes.BPFnVarInput - iface.QDynamicPort = true + iface._enum = nodes.BPFnVarInput + iface._dynamicPort = true }, } @@ -293,8 +293,8 @@ func init() { iface.Title = "FnOutput" iface.Embed.(*fnVarOutputIface).Type = "bp-fnvar-output" - iface.QEnum = nodes.BPFnVarOutput - iface.QDynamicPort = true + iface._enum = nodes.BPFnVarOutput + iface._dynamicPort = true }, } diff --git a/engine/port.go b/engine/port.go index 52c1b6b..c65d1c0 100644 --- a/engine/port.go +++ b/engine/port.go @@ -28,7 +28,7 @@ type Port struct { Value any // Dynamic data (depend on Type) for storing port value (int, string, map, etc..) Sync bool Feature int - QFeature *portFeature // For caching the configuration + _feature *portFeature // For caching the configuration Struct map[string]PortStructTemplate Splitted bool AllowResync bool // Retrigger connected node's .update when the output value is similar @@ -37,14 +37,14 @@ type Port struct { RoutePort *routePort // Internal/Private property - QCache any - QParent *Port - QStructSplitted bool - QGhost bool - QFunc func(*Port) - QCallAll func(*Port) - QOnConnect func(*Cable, *Port) bool - QWaitPortInit func(*Port) + _cache any + _parent *Port + _structSplitted bool + _ghost bool + _func func(*Port) + _callAll func(*Port) + _onConnect func(*Cable, *Port) bool + _waitPortInit func(*Port) } /** For internal library use only */ @@ -77,14 +77,14 @@ type portFeature struct { Func func(*Port) } -func (port *Port) QGetPortFeature() *portFeature { - return port.QFeature +func (port *Port) _getPortFeature() *portFeature { + return port._feature } func (port *Port) DisconnectAll() { - hasRemote := port.Iface.Node.Instance.QRemote == nil + hasRemote := port.Iface.Node.Instance._remote == nil for _, cable := range port.Cables { if hasRemote { - cable.QEvDisconnected = true + cable._evDisconnected = true } cable.Disconnect() @@ -109,7 +109,7 @@ func (port *Port) sync() { continue } - inp.QCache = nil + inp._cache = nil temp := &PortValueEvent{ Target: inp, @@ -126,13 +126,13 @@ func (port *Port) sync() { } node := inpIface.Node - if inpIface.QRequesting == false && len(node.Routes.In) == 0 { + if inpIface._requesting == false && len(node.Routes.In) == 0 { node.Update(cable) - if inpIface.QEnum == nodes.BPFnMain { + if inpIface._enum == nodes.BPFnMain { node.Routes.RouteOut() } else { - inpIface.QProxyInput.Routes.RouteOut() + inpIface._proxyInput.Routes.RouteOut() } } } @@ -161,7 +161,7 @@ type CableErrorEvent struct { Message string } -func (port *Port) QCableConnectError(name string, obj *CableErrorEvent, severe bool) { +func (port *Port) _cableConnectError(name string, obj *CableErrorEvent, severe bool) { msg := "Cable notify: " + name if obj.Iface != nil { msg += "\nIFace: " + obj.Iface.Namespace @@ -186,7 +186,7 @@ func (port *Port) QCableConnectError(name string, obj *CableErrorEvent, severe b } func (port *Port) ConnectCable(cable *Cable) bool { if cable.IsRoute { - port.QCableConnectError("cable.not_route_port", &CableErrorEvent{ + port._cableConnectError("cable.not_route_port", &CableErrorEvent{ Cable: cable, Port: port, Target: cable.Owner, @@ -201,13 +201,13 @@ func (port *Port) ConnectCable(cable *Cable) bool { return false } - if (port.QOnConnect != nil && port.QOnConnect(cable, cable.Owner)) || (cable.Owner.QOnConnect != nil && cable.Owner.QOnConnect(cable, port)) { + if (port._onConnect != nil && port._onConnect(cable, cable.Owner)) || (cable.Owner._onConnect != nil && cable.Owner._onConnect(cable, port)) { return false } // Remove cable if ... if (cable.Source == PortOutput && port.Source != PortInput) /* Output source not connected to input */ || (cable.Source == PortInput && port.Source != PortOutput) /* Input source not connected to output */ { - port.QCableConnectError("cable.wrong_pair", &CableErrorEvent{ + port._cableConnectError("cable.wrong_pair", &CableErrorEvent{ Cable: cable, Port: port, Target: cable.Owner, @@ -219,7 +219,7 @@ func (port *Port) ConnectCable(cable *Cable) bool { if cable.Owner.Source == PortOutput { if (port.Feature == PortTypeArrayOf && !portArrayOf_validate(port, cable.Owner)) || (port.Feature == PortTypeUnion && !portUnion_validate(port, cable.Owner)) { - port.QCableConnectError("cable.wrong_type", &CableErrorEvent{ + port._cableConnectError("cable.wrong_type", &CableErrorEvent{ Cable: cable, Iface: port.Iface, Port: cable.Owner, @@ -231,7 +231,7 @@ func (port *Port) ConnectCable(cable *Cable) bool { } } else if port.Source == PortOutput { if (cable.Owner.Feature == PortTypeArrayOf && !portArrayOf_validate(cable.Owner, port)) || (cable.Owner.Feature == PortTypeUnion && !portUnion_validate(cable.Owner, port)) { - port.QCableConnectError("cable.wrong_type", &CableErrorEvent{ + port._cableConnectError("cable.wrong_type", &CableErrorEvent{ Cable: cable, Iface: port.Iface, Port: port, @@ -259,7 +259,7 @@ func (port *Port) ConnectCable(cable *Cable) bool { // Remove cable if type restriction // if !isInstance || (cable.Owner.Type == types.Function && port.Type != types.Function || cable.Owner.Type != types.Function && port.Type == types.Function) { if cable.Owner.Type == types.Function && port.Type != types.Function || cable.Owner.Type != types.Function && port.Type == types.Function { - port.QCableConnectError("cable.wrong_type_pair", &CableErrorEvent{ + port._cableConnectError("cable.wrong_type_pair", &CableErrorEvent{ Cable: cable, Port: port, Target: cable.Owner, @@ -272,8 +272,8 @@ func (port *Port) ConnectCable(cable *Cable) bool { // Restrict connection between function input/output node with variable node // Connection to similar node function IO or variable node also restricted // These port is created on runtime dynamically - if port.Iface.QDynamicPort && cable.Owner.Iface.QDynamicPort { - port.QCableConnectError("cable.unsupported_dynamic_port", &CableErrorEvent{ + if port.Iface._dynamicPort && cable.Owner.Iface._dynamicPort { + port._cableConnectError("cable.unsupported_dynamic_port", &CableErrorEvent{ Cable: cable, Port: port, Target: cable.Owner, @@ -286,7 +286,7 @@ func (port *Port) ConnectCable(cable *Cable) bool { // Remove cable if there are similar connection for the ports for _, cable := range cable.Owner.Cables { if utils.Contains(port.Cables, cable) { - port.QCableConnectError("cable.duplicate_removed", &CableErrorEvent{ + port._cableConnectError("cable.duplicate_removed", &CableErrorEvent{ Cable: cable, Port: port, Target: cable.Owner, @@ -324,7 +324,7 @@ func (port *Port) ConnectCable(cable *Cable) bool { } if temp != nil { - inp.QCableConnectError("cable.replaced", &CableErrorEvent{ + inp._cableConnectError("cable.replaced", &CableErrorEvent{ Cable: cable, OldCable: temp, Port: inp, @@ -340,14 +340,14 @@ func (port *Port) ConnectCable(cable *Cable) bool { // Connect this cable into port's cable list port.Cables = append(port.Cables, cable) // cable.Connecting() - cable.QConnected() + cable._connected() return true } func (port *Port) ConnectPort(portTarget *Port) bool { cable := newCable(portTarget, port) - if portTarget.QGhost { - cable.QGhost = true + if portTarget._ghost { + cable._ghost = true } portTarget.Cables = append(portTarget.Cables, cable) diff --git a/engine/portFeature.go b/engine/portFeature.go index d63bb27..caaccfb 100644 --- a/engine/portFeature.go +++ b/engine/portFeature.go @@ -46,8 +46,8 @@ func portStructOf_split(port *Port) { for key, val := range *struct_ { name := port.Name + key newPort := node.CreatePort("output", name, val.Type) - newPort.QParent = port - newPort.QStructSplitted = true + newPort._parent = port + newPort._structSplitted = true } port.Splitted = true @@ -60,7 +60,7 @@ func portStructOf_split(port *Port) { } func portStructOf_unsplit(port *Port) { - parent := port.QParent + parent := port._parent if parent == nil && port.Struct != nil { parent = port } diff --git a/engine/portGetterSetter.go b/engine/portGetterSetter.go index 8ca0ccd..c5ab4f5 100644 --- a/engine/portGetterSetter.go +++ b/engine/portGetterSetter.go @@ -14,7 +14,7 @@ func (gs *portInputGetterSetter) Set(val any) { } func (gs *portInputGetterSetter) Call() { - gs.port.QFunc(gs.port) + gs.port._func(gs.port) gs.port.Iface.Node.Routes.RouteOut() } @@ -49,9 +49,9 @@ func (gs *portInputGetterSetter) Get() any { } if target.Value == nil { - port.Iface.QRequesting = true + port.Iface._requesting = true target.Iface.Node.Request(temp) - port.Iface.QRequesting = false + port.Iface._requesting = false } // fmt.Printf("1. %s -> %s (%s)\n", port.Name, target.Name, target.Value) @@ -85,9 +85,9 @@ func (gs *portInputGetterSetter) Get() any { } if target.Value == nil { - port.Iface.QRequesting = true + port.Iface._requesting = true target.Iface.Node.Request(cable) - port.Iface.QRequesting = false + port.Iface._requesting = false } // fmt.Printf("2. %s -> %s (%s)\n", port.Name, target.Name, target.Value) @@ -147,7 +147,7 @@ func (gs *portOutputGetterSetter) Call() { // fmt.Println(cable.String()) if target.Name_ != nil { - target.Iface.QParentFunc.Node.Output[target.Name_.Name].Call() + target.Iface._parentFunc.Node.Output[target.Name_.Name].Call() } else { target.Iface.Node.Input[target.Name].Call() } diff --git a/engine/portGhost.go b/engine/portGhost.go index 111d114..50f0f22 100644 --- a/engine/portGhost.go +++ b/engine/portGhost.go @@ -9,11 +9,11 @@ var fakeIface = &Interface{ } func OutputPort(type_ any) *Port { - port := fakeIface.QCreatePort("Output", "Blackprint.OutputPort", type_) + port := fakeIface._createPort("Output", "Blackprint.OutputPort", type_) return port } func InputPort(type_ any) *Port { - port := fakeIface.QCreatePort("Input", "Blackprint.InputPort", type_) + port := fakeIface._createPort("Input", "Blackprint.InputPort", type_) return port } diff --git a/engine/routePort.go b/engine/routePort.go index 7e55d68..dbbcd46 100644 --- a/engine/routePort.go +++ b/engine/routePort.go @@ -15,7 +15,7 @@ type routePort struct { Iface *Interface // for internal library use only - QIsPaused bool + _isPaused bool } func newRoutePort(iface *Interface) *routePort { @@ -50,7 +50,7 @@ func (r *routePort) RouteTo(iface *Interface) { r.Out = cable port.In = append(port.In, cable) // ToDo: check if this empty if the connected cable was disconnected - cable.QConnected() + cable._connected() } func (r *routePort) ConnectCable(cable *Cable) bool { @@ -61,7 +61,7 @@ func (r *routePort) ConnectCable(cable *Cable) bool { r.In = append(r.In, cable) cable.Input = r.Port cable.Target = r.Port - cable.QConnected() + cable._connected() return true } @@ -80,8 +80,8 @@ func (r *routePort) RouteOut() { } if r.Out == nil { - if r.Iface.QEnum == nodes.BPFnOutput { - node := r.Iface.QFuncMain.Node + if r.Iface._enum == nodes.BPFnOutput { + node := r.Iface._funcMain.Node route := node.Routes route.RouteIn(nil) } @@ -94,15 +94,15 @@ func (r *routePort) RouteOut() { return } - enum := targetRoute.Iface.QEnum + enum := targetRoute.Iface._enum if enum == 0 { targetRoute.RouteIn(r.Out) } else if enum == nodes.BPFnMain { - routes := targetRoute.Iface.QProxyInput.Routes + routes := targetRoute.Iface._proxyInput.Routes routes.RouteIn(r.Out) } else if enum == nodes.BPFnOutput { - node := targetRoute.Iface.QFuncMain.Node + node := targetRoute.Iface._funcMain.Node routes := node.Routes routes.RouteIn(r.Out) } else { From b44fee85ebc7e4ba643199bb6c5a4a8b4d29aa6c Mon Sep 17 00:00:00 2001 From: StefansArya Date: Sat, 10 Sep 2022 01:12:48 +0700 Subject: [PATCH 15/15] Fix route port implementation --- engine/routePort.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/engine/routePort.go b/engine/routePort.go index dbbcd46..acc01f2 100644 --- a/engine/routePort.go +++ b/engine/routePort.go @@ -102,9 +102,8 @@ func (r *routePort) RouteOut() { routes := targetRoute.Iface._proxyInput.Routes routes.RouteIn(r.Out) } else if enum == nodes.BPFnOutput { - node := targetRoute.Iface._funcMain.Node - routes := node.Routes - routes.RouteIn(r.Out) + targetRoute.Iface.Node.Update(nil) + targetRoute.Iface._funcMain.Node.Routes.RouteOut() } else { targetRoute.RouteIn(r.Out) }