Example #1
0
// 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
}
Example #2
0
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
}