|
@@ -8,7 +8,6 @@ import (
|
|
"fmt"
|
|
"fmt"
|
|
"io"
|
|
"io"
|
|
"os"
|
|
"os"
|
|
- "reflect"
|
|
|
|
"sync"
|
|
"sync"
|
|
)
|
|
)
|
|
|
|
|
|
@@ -33,13 +32,10 @@ type Flow struct {
|
|
consts map[string]Data
|
|
consts map[string]Data
|
|
data map[string]Data // Should be named, to fetch later
|
|
data map[string]Data // Should be named, to fetch later
|
|
operations sync.Map
|
|
operations sync.Map
|
|
- //map[string]*opEntry
|
|
|
|
- //err error // should be a list of errors/report
|
|
|
|
- runID int
|
|
|
|
|
|
+ runID int
|
|
|
|
|
|
// Experimental run Event
|
|
// Experimental run Event
|
|
hooks Hooks
|
|
hooks Hooks
|
|
- //func(name string, payLoad map[string]Data)
|
|
|
|
}
|
|
}
|
|
|
|
|
|
// New create a new flow
|
|
// New create a new flow
|
|
@@ -55,21 +51,6 @@ func New() *Flow {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-// Err Set or get current error
|
|
|
|
-/*func (f *Flow) Err(p ...interface{}) error {
|
|
|
|
- f.Lock()
|
|
|
|
- defer f.Unlock()
|
|
|
|
-
|
|
|
|
- if len(p) == 0 {
|
|
|
|
- return f.err
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if err, ok := p[0].(error); ok {
|
|
|
|
- f.err = err
|
|
|
|
- }
|
|
|
|
- return f.err
|
|
|
|
-}*/
|
|
|
|
-
|
|
|
|
//SetRegistry use the registry specified
|
|
//SetRegistry use the registry specified
|
|
func (f *Flow) SetRegistry(r *registry.R) *Flow {
|
|
func (f *Flow) SetRegistry(r *registry.R) *Flow {
|
|
f.registry = r
|
|
f.registry = r
|
|
@@ -83,6 +64,20 @@ func (f *Flow) SetIDGen(idGen func() string) {
|
|
f.idGen = idGen
|
|
f.idGen = idGen
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// Must Helper to return from operations
|
|
|
|
+func (f *Flow) Must(op Operation, err error) Operation {
|
|
|
|
+ if err != nil {
|
|
|
|
+ panic(err)
|
|
|
|
+ }
|
|
|
|
+ return op
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Res returns a deferred operation result
|
|
|
|
+// passing the Id
|
|
|
|
+func (f *Flow) Res(id string) Operation {
|
|
|
|
+ return opFunc(f, id)
|
|
|
|
+}
|
|
|
|
+
|
|
// DefOp Manual tag an Operation
|
|
// DefOp Manual tag an Operation
|
|
func (f *Flow) DefOp(id string, name string, params ...interface{}) (Operation, error) {
|
|
func (f *Flow) DefOp(id string, name string, params ...interface{}) (Operation, error) {
|
|
inputs := make([]*operation, len(params))
|
|
inputs := make([]*operation, len(params))
|
|
@@ -91,7 +86,6 @@ func (f *Flow) DefOp(id string, name string, params ...interface{}) (Operation,
|
|
case *operation:
|
|
case *operation:
|
|
inputs[i] = v
|
|
inputs[i] = v
|
|
default:
|
|
default:
|
|
- //log.Println("WARNING defining const with value", v)
|
|
|
|
c, err := f.Const(v)
|
|
c, err := f.Const(v)
|
|
if err != nil {
|
|
if err != nil {
|
|
return nil, err
|
|
return nil, err
|
|
@@ -108,100 +102,63 @@ func (f *Flow) DefOp(id string, name string, params ...interface{}) (Operation,
|
|
return opFunc(f, id), nil
|
|
return opFunc(f, id), nil
|
|
}
|
|
}
|
|
|
|
|
|
-// Res returns a deferred operation result
|
|
|
|
-// passing the Id
|
|
|
|
-func (f *Flow) Res(id string) Operation {
|
|
|
|
- // Defered operation
|
|
|
|
- return opFunc(f, id)
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
// Op return an function operator
|
|
// Op return an function operator
|
|
// name - a previous registered function
|
|
// name - a previous registered function
|
|
// params - the function inputs
|
|
// params - the function inputs
|
|
func (f *Flow) Op(name string, params ...interface{}) (Operation, error) {
|
|
func (f *Flow) Op(name string, params ...interface{}) (Operation, error) {
|
|
- // Use this on Set?
|
|
|
|
- inputs := make([]*operation, len(params))
|
|
|
|
- for i, p := range params {
|
|
|
|
- switch v := p.(type) {
|
|
|
|
- case *operation:
|
|
|
|
- inputs[i] = v
|
|
|
|
- default:
|
|
|
|
-
|
|
|
|
- c, err := f.Const(v)
|
|
|
|
- if err != nil {
|
|
|
|
- return nil, err
|
|
|
|
- }
|
|
|
|
- // fail here
|
|
|
|
- //log.Println("WARNING defining const with value", v)
|
|
|
|
- inputs[i] = c.(*operation)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ var op Operation
|
|
|
|
+ var err error
|
|
|
|
|
|
- // Grab executor here
|
|
|
|
- executor, err := f.registry.Get(name)
|
|
|
|
- if err != nil {
|
|
|
|
- return nil, err
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- var op *operation
|
|
|
|
- err = f.allocID(func(id string) (Data, error) {
|
|
|
|
- op = opFunc(f, id)
|
|
|
|
- return &opEntry{sync.Mutex{}, name, inputs, executor}, nil
|
|
|
|
|
|
+ allocErr := f.allocID(func(id string) {
|
|
|
|
+ op, err = f.DefOp(id, name, params...)
|
|
})
|
|
})
|
|
- if err != nil {
|
|
|
|
- return nil, err
|
|
|
|
|
|
+ if allocErr != nil {
|
|
|
|
+ return nil, allocErr
|
|
}
|
|
}
|
|
- return op, nil
|
|
|
|
|
|
+ return op, err
|
|
}
|
|
}
|
|
|
|
|
|
-// HasOp verifies if an operation exists
|
|
|
|
-func (f *Flow) HasOp(name string) bool {
|
|
|
|
- _, ret := f.operations.Load(name)
|
|
|
|
- return ret
|
|
|
|
|
|
+// DefErrOp define a nil operation that will return error
|
|
|
|
+// Usefull for builders
|
|
|
|
+func (f *Flow) DefErrOp(id string, err error) (Operation, error) {
|
|
|
|
+ executor := func() error { return err }
|
|
|
|
+ f.operations.Store(id, &opEntry{sync.Mutex{}, fmt.Sprintf("(error)<%v>", err), nil, executor})
|
|
|
|
+ return opFunc(f, id), nil
|
|
}
|
|
}
|
|
|
|
|
|
-// Must it will panic on error
|
|
|
|
-func (f *Flow) Must(op Operation, err error) Operation {
|
|
|
|
- if err != nil {
|
|
|
|
- panic(err)
|
|
|
|
|
|
+// ErrOp error operation with generated ID
|
|
|
|
+func (f *Flow) ErrOp(operr error) (Operation, error) {
|
|
|
|
+ var op Operation
|
|
|
|
+ var err error
|
|
|
|
+
|
|
|
|
+ allocErr := f.allocID(func(id string) {
|
|
|
|
+ op, err = f.DefErrOp(id, operr)
|
|
|
|
+ })
|
|
|
|
+ if allocErr != nil {
|
|
|
|
+ return nil, err
|
|
}
|
|
}
|
|
- return op
|
|
|
|
|
|
+ return op, err
|
|
}
|
|
}
|
|
|
|
|
|
-// DefConst define a const by ID
|
|
|
|
|
|
+// DefConst define a const by defined ID
|
|
func (f *Flow) DefConst(id string, value Data) (Operation, error) {
|
|
func (f *Flow) DefConst(id string, value Data) (Operation, error) {
|
|
f.consts[id] = value
|
|
f.consts[id] = value
|
|
executor := func() Data { return f.consts[id] }
|
|
executor := func() Data { return f.consts[id] }
|
|
- f.operations.Store(id, &opEntry{sync.Mutex{}, fmt.Sprintf("const<%s>", id), nil, executor})
|
|
|
|
|
|
+ f.operations.Store(id, &opEntry{sync.Mutex{}, fmt.Sprintf("(const)<%s>", id), nil, executor})
|
|
return opFunc(f, id), nil
|
|
return opFunc(f, id), nil
|
|
}
|
|
}
|
|
|
|
|
|
-// Const returns a const operation
|
|
|
|
|
|
+// Const returns a const operation with generated ID
|
|
func (f *Flow) Const(value Data) (Operation, error) {
|
|
func (f *Flow) Const(value Data) (Operation, error) {
|
|
-
|
|
|
|
- var op *operation
|
|
|
|
-
|
|
|
|
- err := f.allocID(func(id string) (Data, error) {
|
|
|
|
- f.consts[id] = value
|
|
|
|
- executor := func() Data { return f.consts[id] }
|
|
|
|
- op = opFunc(f, id)
|
|
|
|
- return &opEntry{sync.Mutex{}, fmt.Sprintf("const<%s>", id), nil, executor}, nil
|
|
|
|
-
|
|
|
|
|
|
+ var op Operation
|
|
|
|
+ var err error
|
|
|
|
+ allocErr := f.allocID(func(id string) {
|
|
|
|
+ op, err = f.DefConst(id, value)
|
|
})
|
|
})
|
|
- return op, err
|
|
|
|
- // generate ID
|
|
|
|
- /*for i := 0; i < 10; i++ {
|
|
|
|
- id := f.idGen()
|
|
|
|
- if _, ok := f.consts[id]; ok {
|
|
|
|
- continue
|
|
|
|
- }
|
|
|
|
- return opConst(f, id), nil
|
|
|
|
|
|
+ if allocErr != nil {
|
|
|
|
+ return nil, allocErr
|
|
}
|
|
}
|
|
- return nil, errors.New("ID exausted")*/
|
|
|
|
-
|
|
|
|
- // f.consts[id] = value
|
|
|
|
- // return opFunc(f, id), nil
|
|
|
|
-
|
|
|
|
|
|
+ return op, err
|
|
}
|
|
}
|
|
|
|
|
|
// Var operation
|
|
// Var operation
|
|
@@ -222,41 +179,6 @@ func (f *Flow) In(paramID int) Operation {
|
|
return opIn(f, paramID)
|
|
return opIn(f, paramID)
|
|
}
|
|
}
|
|
|
|
|
|
-// Run a batch of operation?
|
|
|
|
-func (f *Flow) Run(op Operation, params ...Data) (Data, error) {
|
|
|
|
- cache := map[*operation]Data{}
|
|
|
|
- return f.run(cache, op, params...)
|
|
|
|
-}
|
|
|
|
-func (f *Flow) run(cache map[*operation]Data, op Operation, params ...Data) (Data, error) {
|
|
|
|
- o := op.(*operation)
|
|
|
|
- if v, ok := cache[o]; ok {
|
|
|
|
- return v, nil
|
|
|
|
- }
|
|
|
|
- // Manually fetch func data because of caching
|
|
|
|
- var r Data
|
|
|
|
- // This is wrong since the only source of func should be on operation
|
|
|
|
- if o.kind == "func" {
|
|
|
|
- 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
|
|
|
|
- callParam[i] = reflect.ValueOf(fr)
|
|
|
|
- }
|
|
|
|
- r = reflect.ValueOf(op.executor).Call(callParam)[0].Interface()
|
|
|
|
- } else {
|
|
|
|
- var err error
|
|
|
|
- r, err = o.process(nil, params...)
|
|
|
|
- if err != nil {
|
|
|
|
- return nil, err
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- cache[o] = r
|
|
|
|
- return r, nil
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
// Analyse every operations
|
|
// Analyse every operations
|
|
func (f *Flow) Analyse(w io.Writer, params ...Data) {
|
|
func (f *Flow) Analyse(w io.Writer, params ...Data) {
|
|
if w == nil {
|
|
if w == nil {
|
|
@@ -358,7 +280,7 @@ func (f *Flow) MarshalJSON() ([]byte, error) {
|
|
return json.Marshal(data)
|
|
return json.Marshal(data)
|
|
}
|
|
}
|
|
|
|
|
|
-func (f *Flow) allocID(fn func(id string) (Data, error)) error {
|
|
|
|
|
|
+func (f *Flow) allocID(fn func(id string)) error {
|
|
f.Lock()
|
|
f.Lock()
|
|
defer f.Unlock()
|
|
defer f.Unlock()
|
|
|
|
|
|
@@ -369,12 +291,9 @@ func (f *Flow) allocID(fn func(id string) (Data, error)) error {
|
|
if _, ok := f.operations.Load(id); !ok {
|
|
if _, ok := f.operations.Load(id); !ok {
|
|
break
|
|
break
|
|
}
|
|
}
|
|
|
|
+ return errors.New("ID Exausted")
|
|
}
|
|
}
|
|
- entry, err := fn(id)
|
|
|
|
- if err != nil {
|
|
|
|
- return err
|
|
|
|
- }
|
|
|
|
- f.operations.Store(id, entry)
|
|
|
|
|
|
+ fn(id)
|
|
return nil
|
|
return nil
|
|
|
|
|
|
}
|
|
}
|