The mesh runs on the seat's bus alone (novox/hq ADR 0131, design 28 task 5.5). The old transport's consume loop, build request, tool ask, management API and account scoping are deleted, and the bus switch with them; the controller connects to the broker seat and to nothing else. The store-window tests keep their assertions on a bus-less fake, and the tests that only made sense for the old transport's in-memory holding go with it.
63 lines
1.9 KiB
Go
63 lines
1.9 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/novox/mesh-controller/internal/link"
|
|
)
|
|
|
|
// ask calls one of a module's tools, through the control plane's own broker connection.
|
|
//
|
|
// A module serves tools under an account scoped to exactly that (novox/hq ADR 0047), and nothing
|
|
// else in the mesh held an account that could ask one — not an operator at a terminal, not an agent
|
|
// acting for one (novox/hq 04-ISSUES/049). The control plane does, so it is the way in: one
|
|
// process, one connection, one place a question can be seen to have been asked (ADR 0095).
|
|
func askCommand(ctx context.Context, args []string) error {
|
|
positionals, flags := split(args)
|
|
set := flag.NewFlagSet("ask", flag.ContinueOnError)
|
|
wait := set.Duration("wait", 60*time.Second, "how long to wait for the module's answer")
|
|
if err := set.Parse(flags); err != nil {
|
|
return err
|
|
}
|
|
if len(positionals) < 2 || len(positionals) > 3 {
|
|
return errors.New("ask <module> <tool> [json arguments] [--wait 60s]")
|
|
}
|
|
module, tool := positionals[0], positionals[1]
|
|
var arguments json.RawMessage
|
|
if len(positionals) == 3 {
|
|
if !json.Valid([]byte(positionals[2])) {
|
|
return fmt.Errorf("the arguments are not JSON: %s", positionals[2])
|
|
}
|
|
arguments = json.RawMessage(positionals[2])
|
|
}
|
|
|
|
server, err := connectLink(ctx, nil, nil, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer server.Close()
|
|
|
|
answer, err := link.Ask(ctx, server.Bus(), module, tool, arguments, *wait)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// The answer as the module gave it, to standard output, for a person or a program. A tool
|
|
// that answered with an error has still answered: printed the same way, and the exit status
|
|
// says which.
|
|
body, err := json.Marshal(answer)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Fprintln(os.Stdout, string(body))
|
|
if answer.Error != "" {
|
|
return fmt.Errorf("%s.%s answered with an error: %s", module, tool, answer.Error)
|
|
}
|
|
return nil
|
|
}
|