|
@@ -8,6 +8,7 @@ import (
|
|
|
"io"
|
|
|
"os"
|
|
|
"reflect"
|
|
|
+ "sync"
|
|
|
)
|
|
|
|
|
|
// Global
|
|
@@ -21,6 +22,7 @@ var (
|
|
|
type Data = interface{}
|
|
|
|
|
|
type opEntry struct {
|
|
|
+ sync.Mutex
|
|
|
name string
|
|
|
inputs []*operation // still figuring, might be operation
|
|
|
executor interface{}
|
|
@@ -30,18 +32,17 @@ type opEntry struct {
|
|
|
// We could Create a single array of operations
|
|
|
// refs would only mean id, types would be embed in operation
|
|
|
type Flow struct {
|
|
|
- registry *registry.Registry
|
|
|
-
|
|
|
+ registry *registry.Registry
|
|
|
consts map[string]Data
|
|
|
-
|
|
|
data map[string]Data // Should be named, to fetch later
|
|
|
- operations map[string]opEntry
|
|
|
-
|
|
|
+ operations sync.Map
|
|
|
+ //map[string]*opEntry
|
|
|
err error
|
|
|
runID int
|
|
|
|
|
|
// Experimental run Event
|
|
|
- handlers []func(name string, payLoad map[string]Data)
|
|
|
+ hooks Hooks
|
|
|
+ //func(name string, payLoad map[string]Data)
|
|
|
}
|
|
|
|
|
|
// New create a new flow
|
|
@@ -51,7 +52,8 @@ func New() *Flow {
|
|
|
// Data
|
|
|
consts: map[string]Data{},
|
|
|
data: map[string]Data{},
|
|
|
- operations: map[string]opEntry{},
|
|
|
+ operations: sync.Map{},
|
|
|
+ //map[string]opEntry{},
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -85,7 +87,7 @@ func (f *Flow) DefOp(id string, name string, params ...interface{}) Operation {
|
|
|
f.err = err
|
|
|
return opNil(f)
|
|
|
}
|
|
|
- f.operations[id] = opEntry{name, inputs, executor}
|
|
|
+ f.operations.Store(id, &opEntry{sync.Mutex{}, name, inputs, executor})
|
|
|
return opFunc(f, id)
|
|
|
}
|
|
|
|
|
@@ -122,10 +124,10 @@ func (f *Flow) Op(name string, params ...interface{}) Operation {
|
|
|
// generate ID
|
|
|
for {
|
|
|
id := RandString(8)
|
|
|
- if _, ok := f.operations[id]; ok {
|
|
|
+ if _, ok := f.operations.Load(id); ok {
|
|
|
continue
|
|
|
}
|
|
|
- f.operations[id] = opEntry{name, inputs, executor}
|
|
|
+ f.operations.Store(id, &opEntry{sync.Mutex{}, name, inputs, executor})
|
|
|
return opFunc(f, id)
|
|
|
}
|
|
|
// Initialize opfunc maybe
|
|
@@ -179,7 +181,10 @@ func (f *Flow) run(cache map[*operation]Data, op Operation, params ...Data) (Dat
|
|
|
var r Data
|
|
|
// This is wrong since the only source of func should be on operation
|
|
|
if o.kind == "func" {
|
|
|
- op := f.operations[o.id.(string)]
|
|
|
+ op, ok := f.getOp(o.id.(string))
|
|
|
+ if !ok {
|
|
|
+ return nil, fmt.Errorf("Operation %s not found", o.id)
|
|
|
+ }
|
|
|
callParam := make([]reflect.Value, len(op.inputs))
|
|
|
for i, in := range op.inputs {
|
|
|
fr, _ := f.run(cache, in, params...) // ignore error
|
|
@@ -199,10 +204,11 @@ func (f *Flow) Analyse(w io.Writer, params ...Data) {
|
|
|
w = os.Stdout
|
|
|
}
|
|
|
fmt.Fprintf(w, "Ops analysis:\n")
|
|
|
- for k, op := range f.operations {
|
|
|
+ f.operations.Range(func(pk, po interface{}) bool {
|
|
|
+ k, op := pk.(string), po.(*opEntry)
|
|
|
fw := bytes.NewBuffer(nil)
|
|
|
//fmt.Fprintf(w, " [%s] (%v)", k, op.name)
|
|
|
- fmt.Fprintf(fw, " [%s] %s(", k, op.name)
|
|
|
+ fmt.Fprintf(fw, " [%s] %s(", pk, op.name)
|
|
|
for j, in := range op.inputs {
|
|
|
//ref := in.(Op)
|
|
|
if j != 0 {
|
|
@@ -211,7 +217,7 @@ func (f *Flow) Analyse(w io.Writer, params ...Data) {
|
|
|
ires := in.Process(params...)
|
|
|
if f.err != nil {
|
|
|
fmt.Fprintf(w, "Operator: %s error#%s\n", op.name, f.err.Error())
|
|
|
- return
|
|
|
+ return false
|
|
|
}
|
|
|
fmt.Fprintf(fw, " %s[%v](%v)", in.kind, in.id, ires)
|
|
|
}
|
|
@@ -223,7 +229,8 @@ func (f *Flow) Analyse(w io.Writer, params ...Data) {
|
|
|
fmt.Fprintf(fw, "%v\n", res)
|
|
|
|
|
|
fmt.Fprintf(w, "%s", fw.String())
|
|
|
- }
|
|
|
+ return true
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
/////////////////////////////
|
|
@@ -244,7 +251,9 @@ func (f *Flow) String() string {
|
|
|
}
|
|
|
|
|
|
fmt.Fprintf(ret, "funcs:\n")
|
|
|
- for k, v := range f.operations {
|
|
|
+ f.operations.Range(func(pk, pv interface{}) bool {
|
|
|
+ k, v := pk.(string), pv.(*opEntry)
|
|
|
+
|
|
|
fmt.Fprintf(ret, " [%s] %s(", k, v.name)
|
|
|
for j, in := range v.inputs {
|
|
|
if j != 0 {
|
|
@@ -253,7 +262,8 @@ func (f *Flow) String() string {
|
|
|
fmt.Fprintf(ret, "%s[%v]", in.kind, in.id)
|
|
|
}
|
|
|
fmt.Fprintf(ret, ")\n")
|
|
|
- }
|
|
|
+ return true
|
|
|
+ })
|
|
|
|
|
|
return ret.String()
|
|
|
}
|
|
@@ -266,7 +276,8 @@ func (f *Flow) MarshalJSON() ([]byte, error) {
|
|
|
Input []map[string]interface{}
|
|
|
}
|
|
|
operations := map[string]opMarshal{}
|
|
|
- for k, o := range f.operations {
|
|
|
+ f.operations.Range(func(pk, po interface{}) bool {
|
|
|
+ k, o := pk.(string), po.(*opEntry)
|
|
|
refs := []map[string]interface{}{}
|
|
|
for _, in := range o.inputs { // Switch type?
|
|
|
refs = append(refs, map[string]interface{}{
|
|
@@ -275,7 +286,9 @@ func (f *Flow) MarshalJSON() ([]byte, error) {
|
|
|
})
|
|
|
}
|
|
|
operations[k] = opMarshal{o.name, refs}
|
|
|
- }
|
|
|
+ return true
|
|
|
+ })
|
|
|
+
|
|
|
data["operations"] = operations
|
|
|
data["data"] = f.data
|
|
|
data["consts"] = f.consts
|
|
@@ -283,17 +296,23 @@ func (f *Flow) MarshalJSON() ([]byte, error) {
|
|
|
return json.Marshal(data)
|
|
|
}
|
|
|
|
|
|
+/////////////////
|
|
|
+// Async data
|
|
|
+/////
|
|
|
+func (f *Flow) getOp(id string) (*opEntry, bool) {
|
|
|
+
|
|
|
+ o, ok := f.operations.Load(id)
|
|
|
+ if !ok {
|
|
|
+ return nil, false
|
|
|
+ }
|
|
|
+ return o.(*opEntry), true
|
|
|
+}
|
|
|
+
|
|
|
//////////////////////////////////////////////
|
|
|
// Experimental event
|
|
|
////////////////
|
|
|
|
|
|
-// Handle attach a handler
|
|
|
-func (f *Flow) Handle(handler func(name string, payLoad map[string]Data)) {
|
|
|
- f.handlers = append(f.handlers, handler)
|
|
|
-}
|
|
|
-
|
|
|
-func (f *Flow) trigger(name string, payLoad map[string]Data) {
|
|
|
- for _, h := range f.handlers {
|
|
|
- h(name, payLoad)
|
|
|
- }
|
|
|
+// Hook attach the node event hooks
|
|
|
+func (f *Flow) Hook(hook Hook) {
|
|
|
+ f.hooks = append(f.hooks, hook)
|
|
|
}
|