Exemplo n.º 1
0
func sendStartupData(s *seed.Seed, socket socket, runningState string) {
	messages := []executor.MonitorMessage{}

	// _service block content
	messages = append(messages, executor.MonitorMessage{
		Block: "_service",
		Data:  fmt.Sprintf("<code>%s</code>", s.String()[1:]), // skip the beginning newline in the string
	})

	// _graph block content
	dot, err := dot.ToDot(s, s.Name)
	if err != nil {
		panic(err)
	}
	graphviz := exec.Command("dot", "-Tsvg")
	graphviz.Stdin = bytes.NewBuffer(dot)
	graph, err := graphviz.Output()
	if err != nil {
		panic(err)
	}
	messages = append(messages, executor.MonitorMessage{
		Block: "_graph",
		Data:  string(graph), // skip the beginning newline in the string
	})

	// list of collections for input control
	collections := ""
	for name, _ := range s.Collections {
		collections += fmt.Sprintf("<option value=\"%s\">%s</option>", name, name)
	}
	messages = append(messages, executor.MonitorMessage{
		Block: "_collections",
		Data:  collections,
	})

	// runningState
	messages = append(messages, executor.MonitorMessage{
		Block: "_command",
		Data:  runningState,
	})

	for _, message := range messages {
		data, err := json.Marshal(message)
		if err != nil {
			panic(err)
		}

		socket.Write(data)
	}
}
Exemplo n.º 2
0
// Transform uses graphs to add network interfaces to Seeds
func Transform(orig *seed.Seed) (*seed.Seed, error) {
	// build graph
	g := seedGraph.SeedAsGraph(orig)

	orig.Name = strings.Title(orig.Name) + "Server"

	for inputName, input := range orig.Collections {
		if input.Type != seed.CollectionInput {
			continue
		}
		input.Key = append([]string{"@address"}, input.Key...)

		start, ok := g.NodeFor(inputName)
		if !ok {
			panic("could not find node for " + inputName)
		}

		for outputName, output := range orig.Collections {
			if output.Type != seed.CollectionOutput {
				continue
			}
			goal, ok := g.NodeFor(outputName)
			if !ok {
				panic("could not find node for " + outputName)
			}
			path, cost, _ := graph.AStar(start, goal, g, cost, nil)
			if math.IsInf(cost, 0) {
				// there is no path (that does not go through a table)
				continue
			}

			outputAddress := outputName + "_addr"
			previousCollection := inputName
			for _, node := range path[:len(path)] {
				// unbox graph.internalNode;
				node = g.GetNode(node.ID())

				switch node := node.(type) {
				case seedGraph.CollectionNode:
					previousCollection = node.Name
					switch node.Collection.Type {
					case seed.CollectionInput, seed.CollectionScratch:
						node.Collection.Key = prependIfNotExists(node.Collection.Key, outputAddress)
					case seed.CollectionOutput:
						node.Collection.Key = prependIfNotExists(node.Collection.Key, "@"+outputAddress)
					case seed.CollectionChannel, seed.CollectionTable:
						panic("should not encounter these collection types")
					default:
						panic(fmt.Sprintf("unhandled type: %d", node.Collection.Type))
					}
				case seedGraph.RuleNode:
					exists := false
					for _, expression := range node.Rule.Intension {
						switch expression := expression.(type) {
						case seed.QualifiedColumn:
							if expression.Column == outputAddress {
								// if a reference to the outputAddress already exists (i.e., from being added by another flow)
								// then add a constraint to make the rows match up
								node.Rule.Predicate = append(node.Rule.Predicate, seed.Constraint{
									Left: expression,
									Right: seed.QualifiedColumn{
										Collection: previousCollection,
										Column:     outputAddress,
									},
								})
								exists = true
							}
						case seed.MapFunction, seed.ReduceFunction:
							continue
						default:
							panic(fmt.Sprintf("unhandled type: %v", reflect.TypeOf(expression).String()))
						}
					}
					if !exists {
						// add to the projection
						node.Rule.Intension = append([]seed.Expression{seed.QualifiedColumn{
							Collection: previousCollection,
							Column:     outputAddress,
						}}, node.Rule.Intension...)
					}
				default:
					panic(fmt.Sprintf("unhandled type: %v", reflect.TypeOf(node).String()))
				}
			}
		}
	}

	// change inputs and outputs to channels
	for _, collection := range orig.Collections {
		switch collection.Type {
		case seed.CollectionInput, seed.CollectionOutput:
			collection.Type = seed.CollectionChannel
		case seed.CollectionScratch, seed.CollectionTable, seed.CollectionChannel:
			// no-op
		default:
			panic(collection.Type)
		}
	}

	// rules supplying channels must be asynchronous
	for _, rule := range orig.Rules {
		collectionName := rule.Supplies
		collection, ok := orig.Collections[collectionName]
		if !ok {
			// should never happen
			panic(collectionName)
		}

		if collection.Type == seed.CollectionChannel {
			rule.Operation = "<~"
		}
	}

	return orig, nil
}