2018-09-24 18:30:39 +02:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Copyright 2017 gRPC authors.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Package encoding defines the interface for the compressor and codec, and
|
|
|
|
// functions to register and retrieve compressors and codecs.
|
|
|
|
//
|
|
|
|
// This package is EXPERIMENTAL.
|
|
|
|
package encoding
|
|
|
|
|
|
|
|
import (
|
|
|
|
"io"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Identity specifies the optional encoding for uncompressed streams.
|
|
|
|
// It is intended for grpc internal use only.
|
|
|
|
const Identity = "identity"
|
|
|
|
|
|
|
|
// Compressor is used for compressing and decompressing when sending or
|
|
|
|
// receiving messages.
|
|
|
|
type Compressor interface {
|
|
|
|
// Compress writes the data written to wc to w after compressing it. If an
|
|
|
|
// error occurs while initializing the compressor, that error is returned
|
|
|
|
// instead.
|
|
|
|
Compress(w io.Writer) (io.WriteCloser, error)
|
|
|
|
// Decompress reads data from r, decompresses it, and provides the
|
|
|
|
// uncompressed data via the returned io.Reader. If an error occurs while
|
|
|
|
// initializing the decompressor, that error is returned instead.
|
|
|
|
Decompress(r io.Reader) (io.Reader, error)
|
|
|
|
// Name is the name of the compression codec and is used to set the content
|
|
|
|
// coding header. The result must be static; the result cannot change
|
|
|
|
// between calls.
|
|
|
|
Name() string
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
// EXPERIMENTAL: if a Compressor implements
|
|
|
|
// DecompressedSize(compressedBytes []byte) int, gRPC will call it
|
|
|
|
// to determine the size of the buffer allocated for the result of decompression.
|
|
|
|
// Return -1 to indicate unknown size.
|
2018-09-24 18:30:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
var registeredCompressor = make(map[string]Compressor)
|
|
|
|
|
|
|
|
// RegisterCompressor registers the compressor with gRPC by its name. It can
|
|
|
|
// be activated when sending an RPC via grpc.UseCompressor(). It will be
|
|
|
|
// automatically accessed when receiving a message based on the content coding
|
|
|
|
// header. Servers also use it to send a response with the same encoding as
|
|
|
|
// the request.
|
|
|
|
//
|
|
|
|
// NOTE: this function must only be called during initialization time (i.e. in
|
|
|
|
// an init() function), and is not thread-safe. If multiple Compressors are
|
|
|
|
// registered with the same name, the one registered last will take effect.
|
|
|
|
func RegisterCompressor(c Compressor) {
|
|
|
|
registeredCompressor[c.Name()] = c
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetCompressor returns Compressor for the given compressor name.
|
|
|
|
func GetCompressor(name string) Compressor {
|
|
|
|
return registeredCompressor[name]
|
|
|
|
}
|
|
|
|
|
|
|
|
// Codec defines the interface gRPC uses to encode and decode messages. Note
|
|
|
|
// that implementations of this interface must be thread safe; a Codec's
|
|
|
|
// methods can be called from concurrent goroutines.
|
|
|
|
type Codec interface {
|
|
|
|
// Marshal returns the wire format of v.
|
|
|
|
Marshal(v interface{}) ([]byte, error)
|
|
|
|
// Unmarshal parses the wire format into v.
|
|
|
|
Unmarshal(data []byte, v interface{}) error
|
|
|
|
// Name returns the name of the Codec implementation. The returned string
|
|
|
|
// will be used as part of content type in transmission. The result must be
|
|
|
|
// static; the result cannot change between calls.
|
|
|
|
Name() string
|
|
|
|
}
|
|
|
|
|
|
|
|
var registeredCodecs = make(map[string]Codec)
|
|
|
|
|
|
|
|
// RegisterCodec registers the provided Codec for use with all gRPC clients and
|
|
|
|
// servers.
|
|
|
|
//
|
|
|
|
// The Codec will be stored and looked up by result of its Name() method, which
|
|
|
|
// should match the content-subtype of the encoding handled by the Codec. This
|
|
|
|
// is case-insensitive, and is stored and looked up as lowercase. If the
|
|
|
|
// result of calling Name() is an empty string, RegisterCodec will panic. See
|
|
|
|
// Content-Type on
|
|
|
|
// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for
|
|
|
|
// more details.
|
|
|
|
//
|
|
|
|
// NOTE: this function must only be called during initialization time (i.e. in
|
|
|
|
// an init() function), and is not thread-safe. If multiple Compressors are
|
|
|
|
// registered with the same name, the one registered last will take effect.
|
|
|
|
func RegisterCodec(codec Codec) {
|
|
|
|
if codec == nil {
|
|
|
|
panic("cannot register a nil Codec")
|
|
|
|
}
|
2019-09-09 14:04:58 +02:00
|
|
|
if codec.Name() == "" {
|
|
|
|
panic("cannot register Codec with empty string result for Name()")
|
2018-09-24 18:30:39 +02:00
|
|
|
}
|
2019-09-09 14:04:58 +02:00
|
|
|
contentSubtype := strings.ToLower(codec.Name())
|
2018-09-24 18:30:39 +02:00
|
|
|
registeredCodecs[contentSubtype] = codec
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetCodec gets a registered Codec by content-subtype, or nil if no Codec is
|
|
|
|
// registered for the content-subtype.
|
|
|
|
//
|
|
|
|
// The content-subtype is expected to be lowercase.
|
|
|
|
func GetCodec(contentSubtype string) Codec {
|
|
|
|
return registeredCodecs[contentSubtype]
|
|
|
|
}
|