// Runs the component graph with json input and producing json output func Run(js []byte, dec *json.Decoder, enc *json.Encoder, errChan chan<- error) <-chan int { done := make(chan int) graph, err := flow.ParseJSON(js) if err != nil { errChan <- err close(errChan) done <- 1 return done } flow.RunNet(graph) for _, port := range graph.GetUnboundOutPorts() { ch := make(chan execute.ThreadParam) graph.SetOutPort(port.Port, ch) go func() { for a := range ch { if err := enc.Encode(&a); err != nil { errChan <- err } } }() } inPortMap := make(map[string]chan execute.ThreadParam) for _, port := range graph.GetUnboundInPorts() { ch := make(chan execute.ThreadParam) inPortMap[port.Port] = ch graph.SetInPort(port.Port, ch) } go func() { for _, ch := range inPortMap { defer close(ch) } for { var p execute.JSONBlock if err := dec.Decode(&p); err != nil { if err != io.EOF { errChan <- err } return } if p.ID == nil { //TODO add error control in JSONBlock unmarshaling?? errChan <- errors.New("No ID") continue } for k, v := range p.Values { tmp := make(map[string]interface{}) tmp[k] = v sthg, err := json.Marshal(&tmp) if err != nil { continue } if _, exists := inPortMap[k]; exists { param := execute.ThreadParam{ Value: execute.JSONValue{Name: k, JSONString: string(sthg)}, ID: *p.ID, Error: *p.Error, } inPortMap[k] <- param } } } }() go func() { <-graph.Wait() close(errChan) done <- 1 }() return done }
func NewWorkflowRun(id uuid.UUID, wf *Workflow, cf *Config) (*WorkflowRun, error) { params := make(map[flow.FullPortName]interface{}) for _, port := range wf.InPorts { param, ok := cf.Parameters[port.Proc] if !ok { return nil, fmt.Errorf("required parameter not found %v", port) } // Need to unpack fields to map entries; use reflection to avoid // copying pointer based structures pv := reflect.ValueOf(param) fv := pv.Elem().FieldByName(port.Port) if !fv.IsValid() { return nil, fmt.Errorf("required parameter not found %v", port) } reflect.ValueOf(params).SetMapIndex(reflect.ValueOf(port), fv) } ins := make(map[flow.FullPortName]chan execute.ThreadParam) outs := make(map[flow.FullPortName]chan execute.ThreadParam) for _, port := range wf.InPorts { ins[port] = make(chan execute.ThreadParam) wf.Graph.SetInPort(fmt.Sprintf("%s.%s", port.Proc, port.Port), ins[port]) } for _, port := range wf.OutPorts { outs[port] = make(chan execute.ThreadParam) wf.Graph.SetOutPort(fmt.Sprintf("%s.%s", port.Proc, port.Port), outs[port]) } messages := make(chan execute.ThreadParam) errors := make(chan error) done := make(chan bool) // Point of no return... start running workflow flow.RunNet(&wf.Graph) for _, ch := range outs { go func(ch chan execute.ThreadParam) { for v := range ch { messages <- v } }(ch) } tid := execute.ThreadID(id.String()) go func() { defer func() { for _, ch := range ins { close(ch) } }() for port, v := range params { param := execute.ThreadParam{ Value: v, ID: tid, } ins[port] <- param } }() go func() { <-wf.Graph.Wait() close(errors) close(messages) done <- true }() return &WorkflowRun{ ID: id, Outs: outs, Ins: ins, Messages: messages, Errors: errors, Done: done, }, nil }