mirror of https://github.com/docker/docs.git
170 lines
3.4 KiB
Go
170 lines
3.4 KiB
Go
package libswarm
|
|
|
|
import (
|
|
"github.com/docker/libchan"
|
|
"github.com/docker/libchan/data"
|
|
|
|
"fmt"
|
|
"os"
|
|
)
|
|
|
|
type Message struct {
|
|
Verb
|
|
Args []string
|
|
Ret Sender
|
|
Att *os.File
|
|
}
|
|
|
|
type Sender interface {
|
|
Send(msg *Message) (Receiver, error)
|
|
Close() error
|
|
Unwrap() libchan.Sender
|
|
}
|
|
|
|
type Receiver interface {
|
|
Receive(mode int) (*Message, error)
|
|
Unwrap() libchan.Receiver
|
|
}
|
|
|
|
type senderWrapper struct {
|
|
libchan.Sender
|
|
}
|
|
|
|
func WrapSender(s libchan.Sender) Sender {
|
|
return &senderWrapper{s}
|
|
}
|
|
|
|
func (s *senderWrapper) Send(msg *Message) (Receiver, error) {
|
|
recv, err := s.Sender.Send(msg.LibchanMessage())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return WrapReceiver(recv), err
|
|
}
|
|
|
|
func (s *senderWrapper) Unwrap() libchan.Sender {
|
|
return s.Sender
|
|
}
|
|
|
|
type receiverWrapper struct {
|
|
libchan.Receiver
|
|
}
|
|
|
|
func WrapReceiver(r libchan.Receiver) Receiver {
|
|
return &receiverWrapper{r}
|
|
}
|
|
|
|
func (r *receiverWrapper) Receive(mode int) (*Message, error) {
|
|
lcm, err := r.Receiver.Receive(mode)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return DecodeLibchanMessage(lcm)
|
|
}
|
|
|
|
func (r *receiverWrapper) Unwrap() libchan.Receiver {
|
|
return r.Receiver
|
|
}
|
|
|
|
type senderUnwrapper struct {
|
|
Sender
|
|
}
|
|
|
|
func (su *senderUnwrapper) Send(lcm *libchan.Message) (libchan.Receiver, error) {
|
|
msg, err := DecodeLibchanMessage(lcm)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
recv, err := su.Sender.Send(msg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &receiverUnwrapper{recv}, nil
|
|
}
|
|
|
|
type receiverUnwrapper struct {
|
|
Receiver
|
|
}
|
|
|
|
func (ru *receiverUnwrapper) Receive(mode int) (*libchan.Message, error) {
|
|
msg, err := ru.Receiver.Receive(mode)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return msg.LibchanMessage(), nil
|
|
}
|
|
|
|
func Pipe() (Receiver, Sender) {
|
|
r, s := libchan.Pipe()
|
|
return WrapReceiver(r), WrapSender(s)
|
|
}
|
|
|
|
func Copy(s Sender, r Receiver) (int, error) {
|
|
return libchan.Copy(s.Unwrap(), r.Unwrap())
|
|
}
|
|
|
|
func Handler(h func(msg *Message) error) Sender {
|
|
lch := libchan.Handler(func(lcm *libchan.Message) {
|
|
ret := WrapSender(lcm.Ret)
|
|
msg, err := DecodeLibchanMessage(lcm)
|
|
if err != nil {
|
|
ret.Send(&Message{Verb: Error, Args: []string{err.Error()}})
|
|
}
|
|
if err = h(msg); err != nil {
|
|
ret.Send(&Message{Verb: Error, Args: []string{err.Error()}})
|
|
}
|
|
})
|
|
return WrapSender(lch)
|
|
}
|
|
|
|
var RetPipe = WrapSender(libchan.RetPipe)
|
|
var Ret = libchan.Ret
|
|
|
|
var notImplementedMsg = &Message{Verb: Error, Args: []string{"not implemented"}}
|
|
var NotImplemented = WrapSender(libchan.Repeater(notImplementedMsg.LibchanMessage()))
|
|
|
|
func DecodeLibchanMessage(lcm *libchan.Message) (*Message, error) {
|
|
decoded, err := data.Decode(string(lcm.Data))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
verbList, exists := decoded["verb"]
|
|
if !exists {
|
|
return nil, fmt.Errorf("No 'verb' key found in message data: %s", lcm.Data)
|
|
}
|
|
if len(verbList) != 1 {
|
|
return nil, fmt.Errorf("Expected exactly one verb, got %d: %#v", len(verbList), verbList)
|
|
}
|
|
verb, err := VerbFromString(verbList[0])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
args, exists := decoded["args"]
|
|
if !exists {
|
|
return nil, fmt.Errorf("No 'args' key found in message data: %s", lcm.Data)
|
|
}
|
|
return &Message{
|
|
Verb: verb,
|
|
Args: args,
|
|
Ret: WrapSender(lcm.Ret),
|
|
Att: lcm.Fd,
|
|
}, nil
|
|
}
|
|
|
|
func (m *Message) LibchanMessage() *libchan.Message {
|
|
encoded := data.Empty().
|
|
Set("verb", m.Verb.String()).
|
|
Set("args", m.Args...)
|
|
|
|
var ret libchan.Sender
|
|
if m.Ret != nil {
|
|
ret = m.Ret.Unwrap()
|
|
}
|
|
|
|
return &libchan.Message{
|
|
Data: []byte(encoded),
|
|
Ret: ret,
|
|
Fd: m.Att,
|
|
}
|
|
}
|