Example #1
0
// NewServer builds a new server which reads requests from the given Reader
// and writes responses to the given Writer.
func NewServer(r io.Reader, w io.Writer) *Server {
	return &Server{
		r:       NewReader(r),
		w:       NewWriter(w),
		running: atomic.NewBool(false),
	}
}
Example #2
0
// NewClient starts up the given external process and communicates with it over
// stdin and stdout using framed requests and responses.
//
// The Cmd MUST NOT have Stdout or Stdin set.
func NewClient(cmd *exec.Cmd) (*Client, error) {
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return nil, fmt.Errorf("failed to create stdout pipe to %q: %v", cmd.Path, err)
	}

	stdin, err := cmd.StdinPipe()
	if err != nil {
		return nil, fmt.Errorf("failed to create stdin pipe to %q: %v", cmd.Path, err)
	}

	if err := cmd.Start(); err != nil {
		return nil, fmt.Errorf("failed to start %q: %v", cmd.Path, err)
	}

	return &Client{
		stdout:  stdout,
		stdin:   stdin,
		running: atomic.NewBool(true),
		client:  frame.NewClient(stdin, stdout),
		cmd:     cmd,
	}, nil
}
Example #3
0
// NewTransportHandle builds a new Handle which speaks to the given transport.
//
// If the transport is an io.Closer, it will be closed when the handle is closed.
func NewTransportHandle(name string, t envelope.Transport) (Handle, error) {
	client := api.NewPluginClient(multiplex.NewClient(
		"Plugin",
		envelope.NewClient(_proto, t),
	))

	handshake, err := client.Handshake(&api.HandshakeRequest{})
	if err != nil {
		return nil, errHandshakeFailed{Name: name, Reason: err}
	}

	if handshake.Name != name {
		return nil, errHandshakeFailed{
			Name:   name,
			Reason: errNameMismatch{Want: name, Got: handshake.Name},
		}
	}

	if handshake.APIVersion != api.APIVersion {
		return nil, errHandshakeFailed{
			Name:   name,
			Reason: errAPIVersionMismatch{Want: api.APIVersion, Got: handshake.APIVersion},
		}
	}

	// If we got here, the API version matches so the plugin must have
	// provided the Version
	if handshake.LibraryVersion == nil {
		return nil, errHandshakeFailed{
			Name:   name,
			Reason: errVersionIsRequired,
		}
	}

	version, err := semver.Parse(*handshake.LibraryVersion)
	if err != nil {
		return nil, errHandshakeFailed{Name: name, Reason: err}
	}

	if !compatRange.Contains(version) {
		return nil, errHandshakeFailed{
			Name: name,
			Reason: errVersionMismatch{
				Want: compatRange,
				Got:  *handshake.LibraryVersion,
			},
		}
	}

	features := make(map[api.Feature]struct{}, len(handshake.Features))
	for _, feature := range handshake.Features {
		features[feature] = struct{}{}
	}

	return &transportHandle{
		name:      name,
		Transport: t,
		Client:    client,
		Running:   atomic.NewBool(true),
		Features:  features,
	}, nil
}