func (rcv *Receiver) Run() error { r := beam.NewRouter(nil) r.NewRoute().KeyExists("cmd").Handler(func(p []byte, f *os.File) error { // Use the attachment as a beam return channel peer, err := beam.FileConn(f) if err != nil { f.Close() return err } f.Close() defer peer.Close() msg := data.Message(p) cmd := msg.Get("cmd") job := rcv.Engine.Job(cmd[0], cmd[1:]...) // Decode env env, err := data.Decode(msg.GetOne("env")) if err != nil { return fmt.Errorf("error decoding 'env': %v", err) } job.Env().InitMultiMap(env) stdout, err := beam.SendRPipe(peer, data.Empty().Set("cmd", "log", "stdout").Bytes()) if err != nil { return err } job.Stdout.Add(stdout) stderr, err := beam.SendRPipe(peer, data.Empty().Set("cmd", "log", "stderr").Bytes()) if err != nil { return err } job.Stderr.Add(stderr) stdin, err := beam.SendWPipe(peer, data.Empty().Set("cmd", "log", "stdin").Bytes()) if err != nil { return err } job.Stdin.Add(stdin) // ignore error because we pass the raw status job.Run() err = peer.Send(data.Empty().Set("cmd", "status", fmt.Sprintf("%d", job.status)).Bytes(), nil) if err != nil { return err } return nil }) _, err := beam.Copy(r, rcv.peer) return err }
func CmdPrint(args []string, stdout, stderr io.Writer, in beam.Receiver, out beam.Sender) { for { payload, a, err := in.Receive() if err != nil { return } // Skip commands if a != nil && data.Message(payload).Get("cmd") == nil { dup, err := beam.SendRPipe(out, payload) if err != nil { a.Close() return } io.Copy(io.MultiWriter(os.Stdout, dup), a) dup.Close() } else { if err := out.Send(payload, a); err != nil { return } } } }
func Handlers(sink beam.Sender) (*beam.UnixConn, error) { var tasks sync.WaitGroup pub, priv, err := beam.USocketPair() if err != nil { return nil, err } go func() { defer func() { Debugf("[handlers] closewrite() on endpoint\n") // FIXME: this is not yet necessary but will be once // there is synchronization over standard beam messages priv.CloseWrite() Debugf("[handlers] done closewrite() on endpoint\n") }() r := beam.NewRouter(sink) r.NewRoute().HasAttachment().KeyIncludes("type", "job").Handler(func(payload []byte, attachment *os.File) error { conn, err := beam.FileConn(attachment) if err != nil { attachment.Close() return err } // attachment.Close() tasks.Add(1) go func() { defer tasks.Done() defer func() { Debugf("[handlers] '%s' closewrite\n", payload) conn.CloseWrite() Debugf("[handlers] '%s' done closewrite\n", payload) }() cmd := data.Message(payload).Get("cmd") Debugf("[handlers] received %s\n", strings.Join(cmd, " ")) if len(cmd) == 0 { return } handler := GetHandler(cmd[0]) if handler == nil { return } stdout, err := beam.SendRPipe(conn, data.Empty().Set("cmd", "log", "stdout").Set("fromcmd", cmd...).Bytes()) if err != nil { return } defer stdout.Close() stderr, err := beam.SendRPipe(conn, data.Empty().Set("cmd", "log", "stderr").Set("fromcmd", cmd...).Bytes()) if err != nil { return } defer stderr.Close() Debugf("[handlers] calling %s\n", strings.Join(cmd, " ")) handler(cmd, stdout, stderr, beam.Receiver(conn), beam.Sender(conn)) Debugf("[handlers] returned: %s\n", strings.Join(cmd, " ")) }() return nil }) beam.Copy(r, priv) Debugf("[handlers] waiting for all tasks\n") tasks.Wait() Debugf("[handlers] all tasks returned\n") }() return pub, nil }