Merge remote-tracking branch 'origin/master' into jjcollinge/pubsub-context
This commit is contained in:
commit
2e6b84ae40
|
@ -0,0 +1,15 @@
|
|||
coverage:
|
||||
# Commit status https://docs.codecov.io/docs/commit-status are used
|
||||
# to block PR based on coverage threshold.
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
informational: true
|
||||
patch:
|
||||
# Disable the coverage threshold of the patch, so that PRs are
|
||||
# only failing because of overall project coverage threshold.
|
||||
# See https://docs.codecov.io/docs/commit-status#disabling-a-status.
|
||||
default: false
|
||||
comment:
|
||||
# Delete old comment and post new one for new coverage information.
|
||||
behavior: new
|
|
@ -19,3 +19,13 @@ assignees: ''
|
|||
## Steps to Reproduce the Problem
|
||||
|
||||
<!-- How can a maintainer reproduce this issue (be detailed) -->
|
||||
|
||||
## Release Note
|
||||
<!-- How should the fix for this issue be communicated in our release notes? It can be populated later. -->
|
||||
<!-- Keep it as a single line. Examples: -->
|
||||
|
||||
<!-- RELEASE NOTE: **ADD** New feature in Dapr. -->
|
||||
<!-- RELEASE NOTE: **FIX** Bug in runtime. -->
|
||||
<!-- RELEASE NOTE: **UPDATE** Runtime dependency. -->
|
||||
|
||||
RELEASE NOTE:
|
||||
|
|
|
@ -7,3 +7,13 @@ assignees: ''
|
|||
|
||||
---
|
||||
## Describe the feature
|
||||
|
||||
## Release Note
|
||||
<!-- How should this new feature be announced in our release notes? It can be populated later. -->
|
||||
<!-- Keep it as a single line. Examples: -->
|
||||
|
||||
<!-- RELEASE NOTE: **ADD** New feature in Dapr. -->
|
||||
<!-- RELEASE NOTE: **FIX** Bug in runtime. -->
|
||||
<!-- RELEASE NOTE: **UPDATE** Runtime dependency. -->
|
||||
|
||||
RELEASE NOTE:
|
||||
|
|
|
@ -25,7 +25,7 @@ jobs:
|
|||
GOOS: ${{ matrix.target_os }}
|
||||
GOARCH: ${{ matrix.target_arch }}
|
||||
GOPROXY: https://proxy.golang.org
|
||||
GOLANGCI_LINT_VER: v1.26.0
|
||||
GOLANGCI_LINT_VER: v1.31
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
|
@ -49,16 +49,19 @@ jobs:
|
|||
go-version: ${{ env.GOVER }}
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
- name: Install golangci-lint ${{ env.GOLANGCI_LINT_VER }}
|
||||
if: matrix.target_arch != 'arm'
|
||||
run: |
|
||||
curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "${{ env.GOROOT }}/bin" "${{ env.GOLANGCI_LINT_VER }}"
|
||||
- name: Run make lint
|
||||
if: matrix.target_arch != 'arm' && matrix.target_os != 'windows'
|
||||
run: make lint
|
||||
- name: Run golangci-lint
|
||||
if: matrix.target_arch == 'amd64' && matrix.target_os == 'linux'
|
||||
uses: golangci/golangci-lint-action@v2.2.1
|
||||
with:
|
||||
version: ${{ env.GOLANGCI_LINT_VER }}
|
||||
- name: Run make go.mod check-diff
|
||||
if: matrix.target_arch != 'arm'
|
||||
run: make go.mod check-diff
|
||||
- name: Run make test
|
||||
env:
|
||||
COVERAGE_OPTS: "-coverprofile=coverage.txt -covermode=atomic"
|
||||
if: matrix.target_arch != 'arm'
|
||||
run: make test
|
||||
- name: Codecov
|
||||
if: matrix.target_arch == 'amd64' && matrix.target_os == 'linux'
|
||||
uses: codecov/codecov-action@v1
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/dist
|
||||
.idea
|
||||
.vscode
|
||||
.vscode
|
||||
/vendor
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
# These owners are the maintainers and approvers of this repo
|
||||
* @maintainers-components-contrib @approvers-components-contrib
|
|
@ -46,7 +46,7 @@ Before you file an issue, make sure you've checked the following:
|
|||
- 👎 down-vote
|
||||
1. For bugs
|
||||
- Check it's not an environment issue. For example, if running on Kubernetes, make sure prerequisites are in place. (state stores, bindings, etc.)
|
||||
- You have as much data as possible. This usually comes in the form of logs and/or stacktrace. If running on Kubernetes or other environment, look at the logs of the Dapr services (runtime, operator, placement service). More details on how to get logs can be found [here](https://github.com/dapr/docs/tree/master/best-practices/troubleshooting/logs.md).
|
||||
- You have as much data as possible. This usually comes in the form of logs and/or stacktrace. If running on Kubernetes or other environment, look at the logs of the Dapr services (runtime, operator, placement service). More details on how to get logs can be found [here](https://docs.dapr.io/operations/troubleshooting/logs-troubleshooting/).
|
||||
1. For proposals
|
||||
- Many changes to the Dapr runtime may require changes to the API. In that case, the best place to discuss the potential feature is the main [Dapr repo](https://github.com/dapr/dapr).
|
||||
- Other examples could include bindings, state stores or entirely new components.
|
||||
|
|
2
Makefile
2
Makefile
|
@ -51,7 +51,7 @@ endif
|
|||
################################################################################
|
||||
.PHONY: test
|
||||
test:
|
||||
go test ./...
|
||||
go test ./... $(COVERAGE_OPTS)
|
||||
|
||||
################################################################################
|
||||
# Target: lint #
|
||||
|
|
7
OWNERS
7
OWNERS
|
@ -1,7 +0,0 @@
|
|||
maintainers:
|
||||
- yaron2
|
||||
- youngbupark
|
||||
- Haishi2016
|
||||
- lukekim
|
||||
- amanbha
|
||||
- msfussell
|
|
@ -19,8 +19,12 @@ Available component types:
|
|||
* [Secret Stores](secretstores/Readme.md)
|
||||
* [Tracing Exporters](exporters/Readme.md)
|
||||
|
||||
For documentation on how components are being used in Dapr in a language/platform agnostic way, visit [Dapr Docs](https://github.com/dapr/docs).
|
||||
For documentation on how components are being used in Dapr in a language/platform agnostic way, visit [Dapr Docs](https://docs.dapr.io).
|
||||
|
||||
## Contribution
|
||||
|
||||
* [Developing new component](docs/developing-component.md)
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Please refer to our [Dapr Community Code of Conduct](https://github.com/dapr/community/blob/master/CODE-OF-CONDUCT.md)
|
||||
|
|
|
@ -24,5 +24,6 @@ func GetClient(accessKey string, secretKey string, region string, endpoint strin
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return awsSession, nil
|
||||
}
|
||||
|
|
|
@ -9,11 +9,10 @@ import (
|
|||
"flag"
|
||||
"path/filepath"
|
||||
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/util/homedir"
|
||||
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/client-go/util/homedir"
|
||||
)
|
||||
|
||||
// nolint:gochecknoglobals
|
||||
|
@ -42,5 +41,6 @@ func GetKubeClient() (*kubernetes.Clientset, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return clientset, nil
|
||||
}
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
Bindings provide a common way to trigger an application with events from external systems, or invoke an external system with optional data payloads.
|
||||
Bindings are great for event-driven, on-demand compute and help reduce boilerplate code.
|
||||
|
||||
To get started with bindings visit the [How To Guide](https://github.com/dapr/docs/tree/master/howto#resources-bindings).
|
||||
To get started with bindings visit the [How To Guide](https://docs.dapr.io/developing-applications/building-blocks/bindings/howto-bindings/).
|
||||
|
||||
To view all the currently supported bindings visit: [Dapr bindings](https://github.com/dapr/docs/tree/master/concepts/bindings#supported-bindings-and-specs).
|
||||
To view all the currently supported bindings visit: [Dapr bindings](https://docs.dapr.io/operations/components/setup-bindings/supported-bindings/).
|
||||
|
||||
For detailed binding specs visit [Dapr binding specs](https://github.com/dapr/docs/tree/master/reference/specs/bindings).
|
||||
For detailed binding specs visit [Dapr binding specs](https://docs.dapr.io/operations/components/setup-bindings/supported-bindings/).
|
||||
|
||||
## Implementing a new binding
|
||||
|
||||
|
@ -41,4 +41,4 @@ For example, if running a component that takes in a SQL query and returns a resu
|
|||
While components are not restricted to a list of supported operations, it's best to use common ones if the operation kind falls under that operation definition.
|
||||
The list of common operations can be found [here](./requests.go).
|
||||
|
||||
After implementing a binding, the specification docs need to be updated via a PR: [Dapr docs](https://github.com/dapr/docs/tree/master/reference/specs/bindings).
|
||||
After implementing a binding, the specification docs need to be updated via a PR: [Dapr docs](https://docs.dapr.io/operations/components/setup-bindings/supported-bindings/).
|
||||
|
|
|
@ -9,11 +9,10 @@ import (
|
|||
"bytes"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
||||
"github.com/dapr/components-contrib/bindings"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
||||
)
|
||||
|
||||
// AliCloudOSS is a binding for an AliCloud OSS storage bucket
|
||||
|
@ -47,6 +46,7 @@ func (s *AliCloudOSS) Init(metadata bindings.Metadata) error {
|
|||
}
|
||||
s.metadata = m
|
||||
s.client = client
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -63,9 +63,7 @@ func (s *AliCloudOSS) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeRespo
|
|||
s.logger.Debugf("key not found. generating key %s", key)
|
||||
}
|
||||
|
||||
//r := bytes.NewReader(req.Data)
|
||||
bucket, err := s.client.Bucket(s.metadata.Bucket)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -90,12 +88,12 @@ func (s *AliCloudOSS) parseMetadata(metadata bindings.Metadata) (*ossMetadata, e
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
func (s *AliCloudOSS) getClient(metadata *ossMetadata) (*oss.Client, error) {
|
||||
client, err := oss.New(metadata.Endpoint, metadata.AccessKeyID, metadata.AccessKey)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,245 @@
|
|||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
package apns
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"github.com/dapr/components-contrib/bindings"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
)
|
||||
|
||||
const (
|
||||
collapseIDKey = "apns-collapse-id"
|
||||
developmentKey = "development"
|
||||
developmentPrefix = "https://api.sandbox.push.apple.com/3/device/"
|
||||
deviceTokenKey = "device-token"
|
||||
expirationKey = "apns-expiration"
|
||||
keyIDKey = "key-id"
|
||||
messageIDKey = "apns-id"
|
||||
priorityKey = "apns-priority"
|
||||
privateKeyKey = "private-key"
|
||||
productionPrefix = "https://api.push.apple.com/3/device/"
|
||||
pushTypeKey = "apns-push-type"
|
||||
teamIDKey = "team-id"
|
||||
topicKey = "apns-topic"
|
||||
)
|
||||
|
||||
type notificationResponse struct {
|
||||
MessageID string `json:"messageID"`
|
||||
}
|
||||
|
||||
type errorResponse struct {
|
||||
Reason string `json:"reason"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
// APNS implements an outbound binding that allows services to send push
|
||||
// notifications to Apple devices using Apple's Push Notification Service.
|
||||
type APNS struct {
|
||||
logger logger.Logger
|
||||
client *http.Client
|
||||
urlPrefix string
|
||||
authorizationBuilder *authorizationBuilder
|
||||
}
|
||||
|
||||
// NewAPNS will create a new APNS output binding.
|
||||
func NewAPNS(logger logger.Logger) *APNS {
|
||||
return &APNS{
|
||||
logger: logger,
|
||||
client: &http.Client{},
|
||||
authorizationBuilder: &authorizationBuilder{
|
||||
logger: logger,
|
||||
mutex: sync.RWMutex{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Init will configure the APNS output binding using the metadata specified
|
||||
// in the binding's configuration.
|
||||
func (a *APNS) Init(metadata bindings.Metadata) error {
|
||||
if err := a.makeURLPrefix(metadata); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := a.extractKeyID(metadata); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := a.extractTeamID(metadata); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return a.extractPrivateKey(metadata)
|
||||
}
|
||||
|
||||
// Operations will return the set of operations supported by the APNS output
|
||||
// binding. The APNS output binding only supports the "create" operation for
|
||||
// sending new push notifications to the APNS service.
|
||||
func (a *APNS) Operations() []bindings.OperationKind {
|
||||
return []bindings.OperationKind{bindings.CreateOperation}
|
||||
}
|
||||
|
||||
// Invoke is called by Dapr to send a push notification to the APNS output
|
||||
// binding.
|
||||
func (a *APNS) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
|
||||
if req.Operation != bindings.CreateOperation {
|
||||
return nil, fmt.Errorf("operation not supported: %v", req.Operation)
|
||||
}
|
||||
|
||||
return a.sendPushNotification(req)
|
||||
}
|
||||
|
||||
func (a *APNS) sendPushNotification(req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
|
||||
deviceToken, ok := req.Metadata[deviceTokenKey]
|
||||
if !ok || deviceToken == "" {
|
||||
return nil, errors.New("the device-token parameter is required")
|
||||
}
|
||||
|
||||
httpResponse, err := a.sendPushNotificationToAPNS(deviceToken, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer httpResponse.Body.Close()
|
||||
|
||||
if httpResponse.StatusCode == http.StatusOK {
|
||||
return makeSuccessResponse(httpResponse)
|
||||
}
|
||||
|
||||
return makeErrorResponse(httpResponse)
|
||||
}
|
||||
|
||||
func (a *APNS) sendPushNotificationToAPNS(deviceToken string, req *bindings.InvokeRequest) (*http.Response, error) {
|
||||
url := a.urlPrefix + deviceToken
|
||||
httpRequest, err := http.NewRequestWithContext(
|
||||
context.Background(),
|
||||
http.MethodPost,
|
||||
url,
|
||||
bytes.NewReader(req.Data),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
authorizationHeader, err := a.authorizationBuilder.getAuthorizationHeader()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpRequest.Header.Add("authorization", authorizationHeader)
|
||||
addRequestHeader(pushTypeKey, req.Metadata, httpRequest)
|
||||
addRequestHeader(messageIDKey, req.Metadata, httpRequest)
|
||||
addRequestHeader(expirationKey, req.Metadata, httpRequest)
|
||||
addRequestHeader(priorityKey, req.Metadata, httpRequest)
|
||||
addRequestHeader(topicKey, req.Metadata, httpRequest)
|
||||
addRequestHeader(collapseIDKey, req.Metadata, httpRequest)
|
||||
|
||||
return a.client.Do(httpRequest)
|
||||
}
|
||||
|
||||
func (a *APNS) makeURLPrefix(metadata bindings.Metadata) error {
|
||||
if value, ok := metadata.Properties[developmentKey]; ok && value != "" {
|
||||
switch value {
|
||||
case "true":
|
||||
a.logger.Debug("Using the development APNS service")
|
||||
a.urlPrefix = developmentPrefix
|
||||
|
||||
case "false":
|
||||
a.logger.Debug("Using the production APNS service")
|
||||
a.urlPrefix = productionPrefix
|
||||
|
||||
default:
|
||||
return fmt.Errorf(
|
||||
"invalid value for development parameter: %v",
|
||||
value,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
a.logger.Debug("Using the production APNS service")
|
||||
a.urlPrefix = productionPrefix
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *APNS) extractKeyID(metadata bindings.Metadata) error {
|
||||
if value, ok := metadata.Properties[keyIDKey]; ok && value != "" {
|
||||
a.authorizationBuilder.keyID = value
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New("the key-id parameter is required")
|
||||
}
|
||||
|
||||
func (a *APNS) extractTeamID(metadata bindings.Metadata) error {
|
||||
if value, ok := metadata.Properties[teamIDKey]; ok && value != "" {
|
||||
a.authorizationBuilder.teamID = value
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New("the team-id parameter is required")
|
||||
}
|
||||
|
||||
func (a *APNS) extractPrivateKey(metadata bindings.Metadata) error {
|
||||
if value, ok := metadata.Properties[privateKeyKey]; ok && value != "" {
|
||||
block, _ := pem.Decode([]byte(value))
|
||||
if block == nil {
|
||||
return errors.New("unable to read the private key")
|
||||
}
|
||||
|
||||
privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.authorizationBuilder.privateKey = privateKey
|
||||
} else {
|
||||
return errors.New("the private-key parameter is required")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func addRequestHeader(key string, metadata map[string]string, httpRequest *http.Request) {
|
||||
if value, ok := metadata[key]; ok && value != "" {
|
||||
httpRequest.Header.Add(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
func makeSuccessResponse(httpResponse *http.Response) (*bindings.InvokeResponse, error) {
|
||||
messageID := httpResponse.Header.Get(messageIDKey)
|
||||
output := notificationResponse{MessageID: messageID}
|
||||
var data bytes.Buffer
|
||||
encoder := jsoniter.NewEncoder(&data)
|
||||
err := encoder.Encode(output)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &bindings.InvokeResponse{Data: data.Bytes()}, nil
|
||||
}
|
||||
|
||||
func makeErrorResponse(httpResponse *http.Response) (*bindings.InvokeResponse, error) {
|
||||
var errorReply errorResponse
|
||||
decoder := jsoniter.NewDecoder(httpResponse.Body)
|
||||
err := decoder.Decode(&errorReply)
|
||||
if err == nil {
|
||||
err = errors.New(errorReply.Reason)
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
|
@ -0,0 +1,353 @@
|
|||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
package apns
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/dapr/components-contrib/bindings"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const (
|
||||
testKeyID = "012345678"
|
||||
testTeamID = "876543210"
|
||||
|
||||
// This is a valid PKCS #8 payload, but the key was generated for testing
|
||||
// use and is not being used in any production service.
|
||||
testPrivateKey = "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgHZdKErL0xQ3yalg+\nbUMpTpfo4bRVxYMnowSMkBIS3OSgCgYIKoZIzj0DAQehRANCAARjr0Ft+hWAeAfY\nkkOBk8GzMlV4Mo/APwcuXRlAHqkSUKi453YqgAPygkCNBmOhNWgynUp+XGxuj6in\nofsBN1Rw\n-----END PRIVATE KEY-----"
|
||||
)
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
testLogger := logger.NewLogger("test")
|
||||
|
||||
t.Run("uses the development service", func(t *testing.T) {
|
||||
metadata := bindings.Metadata{
|
||||
Properties: map[string]string{
|
||||
developmentKey: "true",
|
||||
keyIDKey: testKeyID,
|
||||
teamIDKey: testTeamID,
|
||||
privateKeyKey: testPrivateKey,
|
||||
},
|
||||
}
|
||||
binding := NewAPNS(testLogger)
|
||||
err := binding.Init(metadata)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, developmentPrefix, binding.urlPrefix)
|
||||
})
|
||||
|
||||
t.Run("uses the production service", func(t *testing.T) {
|
||||
metadata := bindings.Metadata{
|
||||
Properties: map[string]string{
|
||||
developmentKey: "false",
|
||||
keyIDKey: testKeyID,
|
||||
teamIDKey: testTeamID,
|
||||
privateKeyKey: testPrivateKey,
|
||||
},
|
||||
}
|
||||
binding := NewAPNS(testLogger)
|
||||
err := binding.Init(metadata)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, productionPrefix, binding.urlPrefix)
|
||||
})
|
||||
|
||||
t.Run("defaults to the production service", func(t *testing.T) {
|
||||
metadata := bindings.Metadata{
|
||||
Properties: map[string]string{
|
||||
keyIDKey: testKeyID,
|
||||
teamIDKey: testTeamID,
|
||||
privateKeyKey: testPrivateKey,
|
||||
},
|
||||
}
|
||||
binding := NewAPNS(testLogger)
|
||||
err := binding.Init(metadata)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, productionPrefix, binding.urlPrefix)
|
||||
})
|
||||
|
||||
t.Run("invalid development value", func(t *testing.T) {
|
||||
metadata := bindings.Metadata{
|
||||
Properties: map[string]string{
|
||||
developmentKey: "True",
|
||||
keyIDKey: testKeyID,
|
||||
teamIDKey: testTeamID,
|
||||
privateKeyKey: testPrivateKey,
|
||||
},
|
||||
}
|
||||
binding := NewAPNS(testLogger)
|
||||
err := binding.Init(metadata)
|
||||
assert.Error(t, err, "invalid value for development parameter: True")
|
||||
})
|
||||
|
||||
t.Run("the key ID is required", func(t *testing.T) {
|
||||
metadata := bindings.Metadata{
|
||||
Properties: map[string]string{
|
||||
teamIDKey: testTeamID,
|
||||
privateKeyKey: testPrivateKey,
|
||||
},
|
||||
}
|
||||
binding := NewAPNS(testLogger)
|
||||
err := binding.Init(metadata)
|
||||
assert.Error(t, err, "the key-id parameter is required")
|
||||
})
|
||||
|
||||
t.Run("valid key ID", func(t *testing.T) {
|
||||
metadata := bindings.Metadata{
|
||||
Properties: map[string]string{
|
||||
keyIDKey: testKeyID,
|
||||
teamIDKey: testTeamID,
|
||||
privateKeyKey: testPrivateKey,
|
||||
},
|
||||
}
|
||||
binding := NewAPNS(testLogger)
|
||||
err := binding.Init(metadata)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, testKeyID, binding.authorizationBuilder.keyID)
|
||||
})
|
||||
|
||||
t.Run("the team ID is required", func(t *testing.T) {
|
||||
metadata := bindings.Metadata{
|
||||
Properties: map[string]string{
|
||||
keyIDKey: testKeyID,
|
||||
privateKeyKey: testPrivateKey,
|
||||
},
|
||||
}
|
||||
binding := NewAPNS(testLogger)
|
||||
err := binding.Init(metadata)
|
||||
assert.Error(t, err, "the team-id parameter is required")
|
||||
})
|
||||
|
||||
t.Run("valid team ID", func(t *testing.T) {
|
||||
metadata := bindings.Metadata{
|
||||
Properties: map[string]string{
|
||||
keyIDKey: testKeyID,
|
||||
teamIDKey: testTeamID,
|
||||
privateKeyKey: testPrivateKey,
|
||||
},
|
||||
}
|
||||
binding := NewAPNS(testLogger)
|
||||
err := binding.Init(metadata)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, testTeamID, binding.authorizationBuilder.teamID)
|
||||
})
|
||||
|
||||
t.Run("the private key is required", func(t *testing.T) {
|
||||
metadata := bindings.Metadata{
|
||||
Properties: map[string]string{
|
||||
keyIDKey: testKeyID,
|
||||
teamIDKey: testTeamID,
|
||||
},
|
||||
}
|
||||
binding := NewAPNS(testLogger)
|
||||
err := binding.Init(metadata)
|
||||
assert.Error(t, err, "the private-key parameter is required")
|
||||
})
|
||||
|
||||
t.Run("valid private key", func(t *testing.T) {
|
||||
metadata := bindings.Metadata{
|
||||
Properties: map[string]string{
|
||||
keyIDKey: testKeyID,
|
||||
teamIDKey: testTeamID,
|
||||
privateKeyKey: testPrivateKey,
|
||||
},
|
||||
}
|
||||
binding := NewAPNS(testLogger)
|
||||
err := binding.Init(metadata)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, binding.authorizationBuilder.privateKey)
|
||||
})
|
||||
}
|
||||
|
||||
func TestOperations(t *testing.T) {
|
||||
testLogger := logger.NewLogger("test")
|
||||
testBinding := NewAPNS(testLogger)
|
||||
operations := testBinding.Operations()
|
||||
assert.Equal(t, 1, len(operations))
|
||||
assert.Equal(t, bindings.CreateOperation, operations[0])
|
||||
}
|
||||
|
||||
func TestInvoke(t *testing.T) {
|
||||
testLogger := logger.NewLogger("test")
|
||||
|
||||
successRequest := &bindings.InvokeRequest{
|
||||
Operation: bindings.CreateOperation,
|
||||
Metadata: map[string]string{
|
||||
deviceTokenKey: "1234567890",
|
||||
pushTypeKey: "alert",
|
||||
messageIDKey: "123",
|
||||
expirationKey: "1234567890",
|
||||
priorityKey: "10",
|
||||
topicKey: "test",
|
||||
collapseIDKey: "1234567",
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("operation must be create", func(t *testing.T) {
|
||||
testBinding := makeTestBinding(t, testLogger)
|
||||
req := &bindings.InvokeRequest{Operation: bindings.DeleteOperation}
|
||||
_, err := testBinding.Invoke(req)
|
||||
assert.Error(t, err, "operation not supported: delete")
|
||||
})
|
||||
|
||||
t.Run("the device token is required", func(t *testing.T) {
|
||||
testBinding := makeTestBinding(t, testLogger)
|
||||
req := &bindings.InvokeRequest{
|
||||
Operation: bindings.CreateOperation,
|
||||
Metadata: map[string]string{},
|
||||
}
|
||||
_, err := testBinding.Invoke(req)
|
||||
assert.Error(t, err, "the device-token parameter is required")
|
||||
})
|
||||
|
||||
t.Run("the authorization header is sent", func(t *testing.T) {
|
||||
testBinding := makeTestBinding(t, testLogger)
|
||||
testBinding.client = newTestClient(func(req *http.Request) *http.Response {
|
||||
assert.Contains(t, req.Header, "Authorization")
|
||||
|
||||
return successResponse()
|
||||
})
|
||||
_, _ = testBinding.Invoke(successRequest)
|
||||
})
|
||||
|
||||
t.Run("the push type header is sent", func(t *testing.T) {
|
||||
testBinding := makeTestBinding(t, testLogger)
|
||||
testBinding.client = newTestClient(func(req *http.Request) *http.Response {
|
||||
assert.Contains(t, req.Header, "Apns-Push-Type")
|
||||
assert.Equal(t, "alert", req.Header.Get(pushTypeKey))
|
||||
|
||||
return successResponse()
|
||||
})
|
||||
_, _ = testBinding.Invoke(successRequest)
|
||||
})
|
||||
|
||||
t.Run("the message ID is sent", func(t *testing.T) {
|
||||
testBinding := makeTestBinding(t, testLogger)
|
||||
testBinding.client = newTestClient(func(req *http.Request) *http.Response {
|
||||
assert.Contains(t, req.Header, "Apns-Id")
|
||||
assert.Equal(t, "123", req.Header.Get(messageIDKey))
|
||||
|
||||
return successResponse()
|
||||
})
|
||||
_, _ = testBinding.Invoke(successRequest)
|
||||
})
|
||||
|
||||
t.Run("the expiration is sent", func(t *testing.T) {
|
||||
testBinding := makeTestBinding(t, testLogger)
|
||||
testBinding.client = newTestClient(func(req *http.Request) *http.Response {
|
||||
assert.Contains(t, req.Header, "Apns-Expiration")
|
||||
assert.Equal(t, "1234567890", req.Header.Get(expirationKey))
|
||||
|
||||
return successResponse()
|
||||
})
|
||||
_, _ = testBinding.Invoke(successRequest)
|
||||
})
|
||||
|
||||
t.Run("the priority is sent", func(t *testing.T) {
|
||||
testBinding := makeTestBinding(t, testLogger)
|
||||
testBinding.client = newTestClient(func(req *http.Request) *http.Response {
|
||||
assert.Contains(t, req.Header, "Apns-Priority")
|
||||
assert.Equal(t, "10", req.Header.Get(priorityKey))
|
||||
|
||||
return successResponse()
|
||||
})
|
||||
_, _ = testBinding.Invoke(successRequest)
|
||||
})
|
||||
|
||||
t.Run("the topic is sent", func(t *testing.T) {
|
||||
testBinding := makeTestBinding(t, testLogger)
|
||||
testBinding.client = newTestClient(func(req *http.Request) *http.Response {
|
||||
assert.Contains(t, req.Header, "Apns-Topic")
|
||||
assert.Equal(t, "test", req.Header.Get(topicKey))
|
||||
|
||||
return successResponse()
|
||||
})
|
||||
_, _ = testBinding.Invoke(successRequest)
|
||||
})
|
||||
|
||||
t.Run("the collapse ID is sent", func(t *testing.T) {
|
||||
testBinding := makeTestBinding(t, testLogger)
|
||||
testBinding.client = newTestClient(func(req *http.Request) *http.Response {
|
||||
assert.Contains(t, req.Header, "Apns-Collapse-Id")
|
||||
assert.Equal(t, "1234567", req.Header.Get(collapseIDKey))
|
||||
|
||||
return successResponse()
|
||||
})
|
||||
_, _ = testBinding.Invoke(successRequest)
|
||||
})
|
||||
|
||||
t.Run("the message ID is returned", func(t *testing.T) {
|
||||
testBinding := makeTestBinding(t, testLogger)
|
||||
testBinding.client = newTestClient(func(req *http.Request) *http.Response {
|
||||
return successResponse()
|
||||
})
|
||||
response, err := testBinding.Invoke(successRequest)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, response.Data)
|
||||
var body notificationResponse
|
||||
decoder := jsoniter.NewDecoder(bytes.NewReader(response.Data))
|
||||
err = decoder.Decode(&body)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "12345", body.MessageID)
|
||||
})
|
||||
|
||||
t.Run("returns the error code", func(t *testing.T) {
|
||||
testBinding := makeTestBinding(t, testLogger)
|
||||
testBinding.client = newTestClient(func(req *http.Request) *http.Response {
|
||||
body := "{\"reason\":\"BadDeviceToken\"}"
|
||||
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Body: ioutil.NopCloser(strings.NewReader(body)),
|
||||
}
|
||||
})
|
||||
_, err := testBinding.Invoke(successRequest)
|
||||
assert.Error(t, err, "BadDeviceToken")
|
||||
})
|
||||
}
|
||||
|
||||
func makeTestBinding(t *testing.T, log logger.Logger) *APNS {
|
||||
testBinding := NewAPNS(log)
|
||||
bindingMetadata := bindings.Metadata{
|
||||
Properties: map[string]string{
|
||||
developmentKey: "true",
|
||||
keyIDKey: testKeyID,
|
||||
teamIDKey: testTeamID,
|
||||
privateKeyKey: testPrivateKey,
|
||||
},
|
||||
}
|
||||
err := testBinding.Init(bindingMetadata)
|
||||
assert.Nil(t, err)
|
||||
|
||||
return testBinding
|
||||
}
|
||||
|
||||
func successResponse() *http.Response {
|
||||
response := &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Header: http.Header{},
|
||||
}
|
||||
response.Header.Add(messageIDKey, "12345")
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
// http://hassansin.github.io/Unit-Testing-http-client-in-Go
|
||||
|
||||
type roundTripFunc func(req *http.Request) *http.Response
|
||||
|
||||
func (f roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return f(req), nil
|
||||
}
|
||||
|
||||
func newTestClient(fn roundTripFunc) *http.Client {
|
||||
return &http.Client{Transport: fn}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
package apns
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
)
|
||||
|
||||
// The "issued at" timestamp in the JWT must be within one hour from the
|
||||
// APNS server time. I set the expiration time at 55 minutes to ensure that
|
||||
// a new certificate gets generated before it gets too close and risking a
|
||||
// failure.
|
||||
const expirationMinutes = time.Minute * 55
|
||||
|
||||
type authorizationBuilder struct {
|
||||
logger logger.Logger
|
||||
mutex sync.RWMutex
|
||||
authorizationHeader string
|
||||
tokenExpiresAt time.Time
|
||||
keyID string
|
||||
teamID string
|
||||
privateKey interface{}
|
||||
}
|
||||
|
||||
func (a *authorizationBuilder) getAuthorizationHeader() (string, error) {
|
||||
authorizationHeader, ok := a.readAuthorizationHeader()
|
||||
if ok {
|
||||
return authorizationHeader, nil
|
||||
}
|
||||
|
||||
return a.generateAuthorizationHeader()
|
||||
}
|
||||
|
||||
func (a *authorizationBuilder) readAuthorizationHeader() (string, bool) {
|
||||
a.mutex.RLock()
|
||||
defer a.mutex.RUnlock()
|
||||
|
||||
if time.Now().After(a.tokenExpiresAt) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
return a.authorizationHeader, true
|
||||
}
|
||||
|
||||
func (a *authorizationBuilder) generateAuthorizationHeader() (string, error) {
|
||||
a.mutex.Lock()
|
||||
defer a.mutex.Unlock()
|
||||
|
||||
a.logger.Debug("Authorization token expired; generating new token")
|
||||
|
||||
now := time.Now()
|
||||
claims := jwt.StandardClaims{
|
||||
IssuedAt: now.Unix(),
|
||||
Issuer: a.teamID,
|
||||
}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodES256, claims)
|
||||
token.Header["kid"] = a.keyID
|
||||
signedToken, err := token.SignedString(a.privateKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
a.authorizationHeader = "bearer " + signedToken
|
||||
a.tokenExpiresAt = now.Add(expirationMinutes)
|
||||
|
||||
return a.authorizationHeader, nil
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
// Package apns implements an output binding for Dapr that allows services to
|
||||
// send push notifications to Apple devices and Mac computers using Apple's
|
||||
// Push Notification Service (APNS).
|
||||
//
|
||||
// Configuring the Binding
|
||||
//
|
||||
// To use the APNS output binding, you will need to create the binding
|
||||
// configuration and add it to your components directory. The binding
|
||||
// configuration will contain parameters that will allow the binding to
|
||||
// connect to the APNS service specified as metadata.
|
||||
//
|
||||
// The APNS binding will need a cryptographic private key in order to generate
|
||||
// authentication tokens for the APNS service. The private key can be generated
|
||||
// from the Apple Developer Portal and is provided as a PKCS #8 file with the
|
||||
// private key stored in PEM format. The private key should be stored in the
|
||||
// Dapr secret store and not stored directly in the binding's configuration
|
||||
// file.
|
||||
//
|
||||
// A sample configuration file for the APNS binding is shown below:
|
||||
//
|
||||
// apiVersion: dapr.io/v1alpha1
|
||||
// kind: Component
|
||||
// metadata:
|
||||
// name: apns
|
||||
// namespace: default
|
||||
// spec:
|
||||
// type: bindings.apns
|
||||
// metadata:
|
||||
// - name: development
|
||||
// value: false
|
||||
// - name: key-id
|
||||
// value: PUT-KEY-ID-HERE
|
||||
// - name: team-id
|
||||
// value: PUT-APPLE-TEAM-ID-HERE
|
||||
// - name: private-key
|
||||
// secretKeyRef:
|
||||
// name: apns-secrets
|
||||
// key: private-key
|
||||
//
|
||||
// If using Kubernetes, a sample secret configuration may look like this:
|
||||
//
|
||||
// apiVersion: v1
|
||||
// kind: Secret
|
||||
// metadata:
|
||||
// name: apns-secrets
|
||||
// namespace: default
|
||||
// stringData:
|
||||
// private-key: |
|
||||
// -----BEGIN PRIVATE KEY-----
|
||||
// KEY-DATA-GOES-HERE
|
||||
// -----END PRIVATE KEY-----
|
||||
//
|
||||
// The development parameter can be either "true" or "false". The development
|
||||
// parameter controls which APNS service is used. If development is set to
|
||||
// true, then the sandbox APNS service will be used to send push notifications
|
||||
// to devices. If development is set to false, the production APNS service will
|
||||
// be used to send push notifications. If not specified, the production service
|
||||
// will be chosen by default.
|
||||
//
|
||||
// Push Notification Format
|
||||
//
|
||||
// The APNS binding is a pass-through wrapper over the Apple Push Notification
|
||||
// Service. The APNS binding will send the request directly to the APNS service
|
||||
// without any translation. It is therefore important to understand the payload
|
||||
// for push notifications expected by the APNS service. The payload format is
|
||||
// documented at https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification.
|
||||
//
|
||||
// Requests sent to the APNS binding should be a JSON object. A simple push
|
||||
// notification appears below:
|
||||
//
|
||||
// {
|
||||
// "aps": {
|
||||
// "alert": {
|
||||
// "title": "New Updates!",
|
||||
// "body": "New updates are now available for your review."
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// The aps child object contains the push notification details that are used
|
||||
// by the Apple Push Notification Service and target devices to route and show
|
||||
// the push notification. Additional objects or values can be added to the push
|
||||
// notification envelope for use by applications to handle the push
|
||||
// notification.
|
||||
//
|
||||
// The APNS binding accepts several metadata values that are mapped directly
|
||||
// to HTTP headers in the APNS publish request. Below is a summary of the valid
|
||||
// metadata fields. For more information, please see
|
||||
// https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification.
|
||||
//
|
||||
// * apns-push-type: Identifies the content of the notification payload. One of
|
||||
// alert, background, voip, complication, fileprovider, mdm.
|
||||
//
|
||||
// * apns-id: a UUID that uniquely identifies the push notification. This value
|
||||
// is returned by APNS if provided and can be used to track notifications.
|
||||
//
|
||||
// * apns-expiration: The date/time at which the notification is no longer
|
||||
// valid and should not be delivered. This value is the number of seconds
|
||||
// since the UNIX epoch (January 1, 1970 at 00:00 UTC). If not specified or
|
||||
// if 0, the message is sent once immediately and then discarded.
|
||||
//
|
||||
// * apns-priority: If 10, the notification is sent immediately. If 5, the
|
||||
// notification is sent based on power conditions of the user's device.
|
||||
// Defaults to 10.
|
||||
//
|
||||
// * apns-topic: The topic for the notification. Typically this is the bundle
|
||||
// identifier of the target app.
|
||||
//
|
||||
// * apns-collapse-id: A correlation identifier that will cause notifications
|
||||
// to be displayed as a group on the target device. For example, multiple
|
||||
// notifications from a chat room may have the same identifier causing them
|
||||
// to show up together in the device's notifications list.
|
||||
//
|
||||
// Sending a Push Notification Using the APNS Binding
|
||||
//
|
||||
// A simple request to the APNS binding looks like this:
|
||||
//
|
||||
// {
|
||||
// "data": {
|
||||
// "aps": {
|
||||
// "alert": {
|
||||
// "title": "New Updates!",
|
||||
// "body": "New updates are available for your review."
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// "metadata": {
|
||||
// "device-token": "PUT-DEVICE-TOKEN-HERE",
|
||||
// "apns-push-type": "alert",
|
||||
// "apns-priority": "10",
|
||||
// "apns-topic": "com.example.helloworld"
|
||||
// },
|
||||
// "operation": "create"
|
||||
// }
|
||||
//
|
||||
// The device-token metadata field is required and should contain the token
|
||||
// for the device that will receive the push notification. Only one device
|
||||
// can be specified per request to the APNS binding.
|
||||
//
|
||||
// The APNS binding only supports one operation: create. Specifying any other
|
||||
// operation name will result in a runtime error.
|
||||
//
|
||||
// If the push notification is successfully sent, the response will be a JSON
|
||||
// object containing the message ID. If a message ID was not specified using
|
||||
// the apns-id metadata value, then the Apple Push Notification Serivce will
|
||||
// generate a unique ID and will return it.
|
||||
//
|
||||
// {
|
||||
// "messageID": "12345678-1234-1234-1234-1234567890AB"
|
||||
// }
|
||||
//
|
||||
// If the push notification could not be sent due to an authentication error
|
||||
// or payload error, the error code returned by Apple will be returned. For
|
||||
// a list of error codes and their meanings, see
|
||||
// https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/handling_notification_responses_from_apns.
|
||||
package apns
|
|
@ -8,17 +8,15 @@ package dynamodb
|
|||
import (
|
||||
"encoding/json"
|
||||
|
||||
aws_auth "github.com/dapr/components-contrib/authentication/aws"
|
||||
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
|
||||
aws_auth "github.com/dapr/components-contrib/authentication/aws"
|
||||
"github.com/dapr/components-contrib/bindings"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
)
|
||||
|
||||
//DynamoDB allows performing stateful operations on AWS DynamoDB
|
||||
// DynamoDB allows performing stateful operations on AWS DynamoDB
|
||||
type DynamoDB struct {
|
||||
client *dynamodb.DynamoDB
|
||||
table string
|
||||
|
@ -52,6 +50,7 @@ func (d *DynamoDB) Init(metadata bindings.Metadata) error {
|
|||
|
||||
d.client = client
|
||||
d.table = meta.Table
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -95,6 +94,7 @@ func (d *DynamoDB) getDynamoDBMetadata(spec bindings.Metadata) (*dynamoDBMetadat
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &meta, nil
|
||||
}
|
||||
|
||||
|
@ -105,5 +105,6 @@ func (d *DynamoDB) getClient(metadata *dynamoDBMetadata) (*dynamodb.DynamoDB, er
|
|||
}
|
||||
|
||||
c := dynamodb.New(sess)
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
|
|
@ -15,12 +15,11 @@ import (
|
|||
"syscall"
|
||||
"time"
|
||||
|
||||
aws_auth "github.com/dapr/components-contrib/authentication/aws"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/service/kinesis"
|
||||
aws_auth "github.com/dapr/components-contrib/authentication/aws"
|
||||
"github.com/dapr/components-contrib/bindings"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
"github.com/google/uuid"
|
||||
|
@ -55,10 +54,10 @@ type kinesisMetadata struct {
|
|||
type kinesisConsumerMode string
|
||||
|
||||
const (
|
||||
//ExtendedFanout - dedicated throughput through data stream api
|
||||
// ExtendedFanout - dedicated throughput through data stream api
|
||||
ExtendedFanout kinesisConsumerMode = "extended"
|
||||
|
||||
//SharedThroughput - shared throughput using checkpoint and monitoring
|
||||
// SharedThroughput - shared throughput using checkpoint and monitoring
|
||||
SharedThroughput kinesisConsumerMode = "shared"
|
||||
|
||||
partitionKeyName = "partitionKey"
|
||||
|
@ -104,7 +103,6 @@ func (a *AWSKinesis) Init(metadata bindings.Metadata) error {
|
|||
stream, err := client.DescribeStream(&kinesis.DescribeStreamInput{
|
||||
StreamName: streamName,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -119,6 +117,7 @@ func (a *AWSKinesis) Init(metadata bindings.Metadata) error {
|
|||
a.streamARN = stream.StreamDescription.StreamARN
|
||||
a.metadata = m
|
||||
a.client = client
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -136,6 +135,7 @@ func (a *AWSKinesis) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeRespon
|
|||
Data: req.Data,
|
||||
PartitionKey: &partitionKey,
|
||||
})
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -173,6 +173,7 @@ func (a *AWSKinesis) Subscribe(ctx context.Context, streamDesc kinesis.StreamDes
|
|||
consumerARN, err := a.ensureConsumer(streamDesc.StreamARN)
|
||||
if err != nil {
|
||||
a.logger.Error(err)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -189,9 +190,9 @@ func (a *AWSKinesis) Subscribe(ctx context.Context, streamDesc kinesis.StreamDes
|
|||
ShardId: s.ShardId,
|
||||
StartingPosition: &kinesis.StartingPosition{Type: aws.String(kinesis.ShardIteratorTypeLatest)},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
a.logger.Error(err)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -219,9 +220,9 @@ func (a *AWSKinesis) ensureConsumer(streamARN *string) (*string, error) {
|
|||
ConsumerName: &a.metadata.ConsumerName,
|
||||
StreamARN: streamARN,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
arn, err := a.registerConsumer(streamARN)
|
||||
|
||||
return arn, err
|
||||
}
|
||||
|
||||
|
@ -233,7 +234,6 @@ func (a *AWSKinesis) registerConsumer(streamARN *string) (*string, error) {
|
|||
ConsumerName: &a.metadata.ConsumerName,
|
||||
StreamARN: streamARN,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -257,6 +257,7 @@ func (a *AWSKinesis) deregisterConsumer(streamARN *string, consumerARN *string)
|
|||
StreamARN: streamARN,
|
||||
ConsumerName: &a.metadata.ConsumerName,
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -284,6 +285,7 @@ func (a *AWSKinesis) waitUntilConsumerExists(ctx aws.Context, input *kinesis.Des
|
|||
req, _ := a.client.DescribeStreamConsumerRequest(inCpy)
|
||||
req.SetContext(ctx)
|
||||
req.ApplyOptions(opts...)
|
||||
|
||||
return req, nil
|
||||
},
|
||||
}
|
||||
|
@ -299,6 +301,7 @@ func (a *AWSKinesis) getClient(metadata *kinesisMetadata) (*kinesis.Kinesis, err
|
|||
}
|
||||
|
||||
k := kinesis.New(sess)
|
||||
|
||||
return k, nil
|
||||
}
|
||||
|
||||
|
@ -313,6 +316,7 @@ func (a *AWSKinesis) parseMetadata(metadata bindings.Metadata) (*kinesisMetadata
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -9,14 +9,12 @@ import (
|
|||
"bytes"
|
||||
"encoding/json"
|
||||
|
||||
aws_auth "github.com/dapr/components-contrib/authentication/aws"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
||||
aws_auth "github.com/dapr/components-contrib/authentication/aws"
|
||||
"github.com/dapr/components-contrib/bindings"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AWSS3 is a binding for an AWS S3 storage bucket
|
||||
|
@ -51,6 +49,7 @@ func (s *AWSS3) Init(metadata bindings.Metadata) error {
|
|||
}
|
||||
s.metadata = m
|
||||
s.uploader = uploader
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -73,6 +72,7 @@ func (s *AWSS3) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeResponse, e
|
|||
Key: aws.String(key),
|
||||
Body: r,
|
||||
})
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,7 @@ func (s *AWSS3) parseMetadata(metadata bindings.Metadata) (*s3Metadata, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
|
@ -97,5 +98,6 @@ func (s *AWSS3) getClient(metadata *s3Metadata) (*s3manager.Uploader, error) {
|
|||
}
|
||||
|
||||
uploader := s3manager.NewUploader(sess)
|
||||
|
||||
return uploader, nil
|
||||
}
|
||||
|
|
|
@ -9,12 +9,10 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
aws_auth "github.com/dapr/components-contrib/authentication/aws"
|
||||
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/sns"
|
||||
aws_auth "github.com/dapr/components-contrib/authentication/aws"
|
||||
"github.com/dapr/components-contrib/bindings"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
)
|
||||
|
||||
// AWSSNS is an AWS SNS binding
|
||||
|
@ -55,6 +53,7 @@ func (a *AWSSNS) Init(metadata bindings.Metadata) error {
|
|||
}
|
||||
a.client = client
|
||||
a.topicARN = m.TopicArn
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -69,6 +68,7 @@ func (a *AWSSNS) parseMetadata(metadata bindings.Metadata) (*snsMetadata, error)
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
|
@ -78,6 +78,7 @@ func (a *AWSSNS) getClient(metadata *snsMetadata) (*sns.SNS, error) {
|
|||
return nil, err
|
||||
}
|
||||
c := sns.New(sess)
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
|
@ -105,5 +106,6 @@ func (a *AWSSNS) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeResponse,
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ func (a *AWSSQS) Init(metadata bindings.Metadata) error {
|
|||
|
||||
a.QueueURL = resultURL.QueueUrl
|
||||
a.Client = client
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -72,6 +73,7 @@ func (a *AWSSQS) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeResponse,
|
|||
MessageBody: &msgBody,
|
||||
QueueUrl: a.QueueURL,
|
||||
})
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -125,6 +127,7 @@ func (a *AWSSQS) parseSQSMetadata(metadata bindings.Metadata) (*sqsMetadata, err
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
package blobstorage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
b64 "encoding/base64"
|
||||
"encoding/json"
|
||||
|
@ -13,21 +14,21 @@ import (
|
|||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/Azure/azure-storage-blob-go/azblob"
|
||||
"github.com/dapr/components-contrib/bindings"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const (
|
||||
blobName = "blobName"
|
||||
contentType = "ContentType"
|
||||
contentMD5 = "ContentMD5"
|
||||
contentEncoding = "ContentEncoding"
|
||||
contentLanguage = "ContentLanguage"
|
||||
contentDisposition = "ContentDisposition"
|
||||
cacheControl = "CacheControl"
|
||||
blobName = "blobName"
|
||||
contentType = "ContentType"
|
||||
contentMD5 = "ContentMD5"
|
||||
contentEncoding = "ContentEncoding"
|
||||
contentLanguage = "ContentLanguage"
|
||||
contentDisposition = "ContentDisposition"
|
||||
cacheControl = "CacheControl"
|
||||
defaultGetBlobRetryCount = 10
|
||||
)
|
||||
|
||||
// AzureBlobStorage allows saving blobs to an Azure Blob Storage account
|
||||
|
@ -39,9 +40,15 @@ type AzureBlobStorage struct {
|
|||
}
|
||||
|
||||
type blobStorageMetadata struct {
|
||||
StorageAccount string `json:"storageAccount"`
|
||||
StorageAccessKey string `json:"storageAccessKey"`
|
||||
Container string `json:"container"`
|
||||
StorageAccount string `json:"storageAccount"`
|
||||
StorageAccessKey string `json:"storageAccessKey"`
|
||||
Container string `json:"container"`
|
||||
DecodeBase64 string `json:"decodeBase64"`
|
||||
GetBlobRetryCount int `json:"getBlobRetryCount"`
|
||||
}
|
||||
|
||||
type createResponse struct {
|
||||
BlobURL string `json:"blobURL"`
|
||||
}
|
||||
|
||||
// NewAzureBlobStorage returns a new Azure Blob Storage instance
|
||||
|
@ -72,6 +79,7 @@ func (a *AzureBlobStorage) Init(metadata bindings.Metadata) error {
|
|||
// Don't return error, container might already exist
|
||||
a.logger.Debugf("error creating container: %s", err)
|
||||
a.containerURL = containerURL
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -87,23 +95,19 @@ func (a *AzureBlobStorage) parseMetadata(metadata bindings.Metadata) (*blobStora
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if m.GetBlobRetryCount == 0 {
|
||||
m.GetBlobRetryCount = defaultGetBlobRetryCount
|
||||
}
|
||||
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
func (a *AzureBlobStorage) Operations() []bindings.OperationKind {
|
||||
return []bindings.OperationKind{bindings.CreateOperation}
|
||||
return []bindings.OperationKind{bindings.CreateOperation, bindings.GetOperation}
|
||||
}
|
||||
|
||||
func (a *AzureBlobStorage) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
|
||||
name := ""
|
||||
if val, ok := req.Metadata[blobName]; ok && val != "" {
|
||||
name = val
|
||||
delete(req.Metadata, blobName)
|
||||
} else {
|
||||
name = uuid.New().String()
|
||||
}
|
||||
blobURL := a.containerURL.NewBlockBlobURL(name)
|
||||
|
||||
func (a *AzureBlobStorage) create(blobURL azblob.BlockBlobURL, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
|
||||
var blobHTTPHeaders azblob.BlobHTTPHeaders
|
||||
if val, ok := req.Metadata[contentType]; ok && val != "" {
|
||||
blobHTTPHeaders.ContentType = val
|
||||
|
@ -135,12 +139,82 @@ func (a *AzureBlobStorage) Invoke(req *bindings.InvokeRequest) (*bindings.Invoke
|
|||
}
|
||||
|
||||
// Unescape data which will still be a JSON string
|
||||
unescapedData, _ := strconv.Unquote(string(req.Data))
|
||||
unescapedData, unescapeError := strconv.Unquote(string(req.Data))
|
||||
|
||||
_, err := azblob.UploadBufferToBlockBlob(context.Background(), []byte(unescapedData), blobURL, azblob.UploadToBlockBlobOptions{
|
||||
if unescapeError != nil {
|
||||
return nil, unescapeError
|
||||
}
|
||||
|
||||
data := []byte(unescapedData)
|
||||
|
||||
// The "true" is the only allowed positive value. Other positive variations like "True" not acceptable.
|
||||
if a.metadata.DecodeBase64 == "true" {
|
||||
decoded, decodeError := b64.StdEncoding.DecodeString(unescapedData)
|
||||
if decodeError != nil {
|
||||
return nil, decodeError
|
||||
}
|
||||
data = decoded
|
||||
}
|
||||
|
||||
_, err := azblob.UploadBufferToBlockBlob(context.Background(), data, blobURL, azblob.UploadToBlockBlobOptions{
|
||||
Parallelism: 16,
|
||||
Metadata: req.Metadata,
|
||||
BlobHTTPHeaders: blobHTTPHeaders,
|
||||
})
|
||||
return nil, err
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error uploading az blob: %s", err)
|
||||
}
|
||||
|
||||
resp := createResponse{
|
||||
BlobURL: blobURL.String(),
|
||||
}
|
||||
b, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error marshalling create response for azure blob: %s", err)
|
||||
}
|
||||
|
||||
return &bindings.InvokeResponse{
|
||||
Data: b,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *AzureBlobStorage) get(blobURL azblob.BlockBlobURL, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
|
||||
resp, err := blobURL.Download(context.TODO(), 0, azblob.CountToEnd, azblob.BlobAccessConditions{}, false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error downloading az blob: %s", err)
|
||||
}
|
||||
|
||||
bodyStream := resp.Body(azblob.RetryReaderOptions{MaxRetryRequests: a.metadata.GetBlobRetryCount})
|
||||
|
||||
b := bytes.Buffer{}
|
||||
_, err = b.ReadFrom(bodyStream)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading az blob body: %s", err)
|
||||
}
|
||||
|
||||
return &bindings.InvokeResponse{
|
||||
Data: b.Bytes(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *AzureBlobStorage) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
|
||||
name := ""
|
||||
if val, ok := req.Metadata[blobName]; ok && val != "" {
|
||||
name = val
|
||||
delete(req.Metadata, blobName)
|
||||
} else {
|
||||
name = uuid.New().String()
|
||||
}
|
||||
|
||||
blobURL := a.containerURL.NewBlockBlobURL(name)
|
||||
switch req.Operation {
|
||||
case bindings.CreateOperation:
|
||||
return a.create(blobURL, req)
|
||||
case bindings.GetOperation:
|
||||
return a.get(blobURL, req)
|
||||
case bindings.DeleteOperation, bindings.ListOperation:
|
||||
fallthrough
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported operation %s", req.Operation)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,12 @@ import (
|
|||
|
||||
func TestParseMetadata(t *testing.T) {
|
||||
m := bindings.Metadata{}
|
||||
m.Properties = map[string]string{"storageAccount": "account", "storageAccessKey": "key", "container": "test"}
|
||||
m.Properties = map[string]string{"storageAccount": "account", "storageAccessKey": "key", "container": "test", "decodeBase64": "true"}
|
||||
blonStorage := NewAzureBlobStorage(logger.NewLogger("test"))
|
||||
meta, err := blonStorage.parseMetadata(m)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "test", meta.Container)
|
||||
assert.Equal(t, "account", meta.StorageAccount)
|
||||
assert.Equal(t, "key", meta.StorageAccessKey)
|
||||
assert.Equal(t, "true", meta.DecodeBase64)
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ func (c *CosmosDB) Init(metadata bindings.Metadata) error {
|
|||
|
||||
c.collection = &colls[0]
|
||||
c.client = client
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -94,6 +95,7 @@ func (c *CosmosDB) parseMetadata(metadata bindings.Metadata) (*cosmosDBCredentia
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &creds, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ func TestPartitionKeyValue(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
assert.Equal(t, "earth", val)
|
||||
|
||||
//Invalid nested partition key
|
||||
// Invalid nested partition key
|
||||
_, err = cosmosDB.getPartitionKeyValue("address.notexists", obj)
|
||||
assert.NotNil(t, err)
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/preview/eventgrid/mgmt/2020-04-01-preview/eventgrid"
|
||||
|
@ -115,6 +114,7 @@ func (a *AzureEventGrid) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeRe
|
|||
err := a.ensureOutputBindingMetadata()
|
||||
if err != nil {
|
||||
a.logger.Error(err.Error())
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -133,12 +133,14 @@ func (a *AzureEventGrid) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeRe
|
|||
err = client.Do(request, response)
|
||||
if err != nil {
|
||||
a.logger.Error(err.Error())
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if response.StatusCode() != fasthttp.StatusOK {
|
||||
body := response.Body()
|
||||
a.logger.Error(string(body))
|
||||
|
||||
return nil, errors.New(string(body))
|
||||
}
|
||||
|
||||
|
@ -174,10 +176,12 @@ func (a *AzureEventGrid) ensureInputBindingMetadata() error {
|
|||
func (a *AzureEventGrid) ensureOutputBindingMetadata() error {
|
||||
if a.metadata.AccessKey == "" {
|
||||
msg := fmt.Sprintf("metadata field 'AccessKey' is empty in EventGrid binding (%s)", a.metadata.Name)
|
||||
|
||||
return errors.New(msg)
|
||||
}
|
||||
if a.metadata.TopicEndpoint == "" {
|
||||
msg := fmt.Sprintf("metadata field 'TopicEndpoint' is empty in EventGrid binding (%s)", a.metadata.Name)
|
||||
|
||||
return errors.New(msg)
|
||||
}
|
||||
|
||||
|
@ -205,6 +209,7 @@ func (a *AzureEventGrid) parseMetadata(metadata bindings.Metadata) (*azureEventG
|
|||
if eventGridMetadata.EventSubscriptionName == "" {
|
||||
eventGridMetadata.EventSubscriptionName = metadata.Name
|
||||
}
|
||||
|
||||
return &eventGridMetadata, nil
|
||||
}
|
||||
|
||||
|
@ -243,6 +248,7 @@ func (a *AzureEventGrid) createSubscription() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return errors.New(string(bodyBytes))
|
||||
}
|
||||
|
||||
|
|
|
@ -91,6 +91,7 @@ func (a *AzureEventHubs) Init(metadata bindings.Metadata) error {
|
|||
}
|
||||
|
||||
a.hub = hub
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -203,6 +204,7 @@ func (a *AzureEventHubs) RegisterPartitionedEventProcessor(handler func(*binding
|
|||
Data: event.Data,
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -233,6 +235,7 @@ func contains(arr []string, str string) bool {
|
|||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -250,7 +253,6 @@ func (a *AzureEventHubs) RegisterEventProcessor(handler func(*bindings.ReadRespo
|
|||
}
|
||||
|
||||
processor, err := eph.NewFromConnectionString(context.Background(), a.metadata.connectionString, leaserCheckpointer, leaserCheckpointer, eph.WithNoBanner(), eph.WithConsumerGroup(a.metadata.consumerGroup))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -58,7 +58,8 @@ func TestParseMetadata(t *testing.T) {
|
|||
"missing storageContainerName",
|
||||
map[string]string{consumerGroup: "fake", connectionString: "fake", storageAccountName: "name", storageAccountKey: "key"},
|
||||
missingStorageContainerNameErrorMsg,
|
||||
}}
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range invalidConfigTestCases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
|
|
|
@ -69,6 +69,7 @@ func (a *AzureServiceBusQueues) Init(metadata bindings.Metadata) error {
|
|||
for _, q := range queues {
|
||||
if q.Name == a.metadata.QueueName {
|
||||
entity = q
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -97,6 +98,7 @@ func (a *AzureServiceBusQueues) Init(metadata bindings.Metadata) error {
|
|||
return err
|
||||
}
|
||||
a.client = client
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -164,11 +166,13 @@ func (a *AzureServiceBusQueues) Read(handler func(*bindings.ReadResponse) error)
|
|||
if err == nil {
|
||||
return msg.Complete(ctx)
|
||||
}
|
||||
|
||||
return msg.Abandon(ctx)
|
||||
}
|
||||
|
||||
if err := a.client.Receive(context.Background(), sbHandler); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ package signalr
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
@ -119,7 +120,7 @@ func (s *SignalR) resolveAPIURL(req *bindings.InvokeRequest) (string, error) {
|
|||
}
|
||||
|
||||
func (s *SignalR) sendMessageToSignalR(url string, token string, data []byte) error {
|
||||
httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
|
||||
httpReq, err := http.NewRequestWithContext(context.Background(), "POST", url, bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -160,6 +160,7 @@ func (t *mockTransport) reset() {
|
|||
func (t *mockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
atomic.AddInt32(&t.requestCount, 1)
|
||||
t.request = req
|
||||
|
||||
return t.response, t.errToReturn
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ func (d *AzureQueueHelper) Init(accountName string, accountKey string, queueName
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -75,6 +76,7 @@ func (d *AzureQueueHelper) Write(data []byte, ttl *time.Duration) error {
|
|||
ttl = &ttlToUse
|
||||
}
|
||||
_, err := messagesURL.Enqueue(ctx, s, time.Second*0, *ttl)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -87,6 +89,7 @@ func (d *AzureQueueHelper) Read(ctx context.Context, consumer *consumer) error {
|
|||
if res.NumMessages() == 0 {
|
||||
// Queue was empty so back off by 10 seconds before trying again
|
||||
time.Sleep(10 * time.Second)
|
||||
|
||||
return nil
|
||||
}
|
||||
mt := res.Message(0).Text
|
||||
|
@ -116,6 +119,7 @@ func (d *AzureQueueHelper) Read(ctx context.Context, consumer *consumer) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -165,6 +169,7 @@ func (a *AzureStorageQueues) Init(metadata bindings.Metadata) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -210,6 +215,7 @@ func (a *AzureStorageQueues) Invoke(req *bindings.InvokeRequest) (*bindings.Invo
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -24,11 +24,13 @@ type MockHelper struct {
|
|||
|
||||
func (m *MockHelper) Init(accountName string, accountKey string, queueName string, decodeBase64 bool) error {
|
||||
retvals := m.Called(accountName, accountKey, queueName, decodeBase64)
|
||||
|
||||
return retvals.Error(0)
|
||||
}
|
||||
|
||||
func (m *MockHelper) Write(data []byte, ttl *time.Duration) error {
|
||||
retvals := m.Called(data, ttl)
|
||||
|
||||
return retvals.Error(0)
|
||||
}
|
||||
|
||||
|
@ -141,9 +143,10 @@ func TestReadQueue(t *testing.T) {
|
|||
|
||||
assert.Nil(t, err)
|
||||
|
||||
var handler = func(data *bindings.ReadResponse) error {
|
||||
handler := func(data *bindings.ReadResponse) error {
|
||||
s := string(data.Data)
|
||||
assert.Equal(t, s, "This is my message")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -175,9 +178,10 @@ func TestReadQueueDecode(t *testing.T) {
|
|||
|
||||
assert.Nil(t, err)
|
||||
|
||||
var handler = func(data *bindings.ReadResponse) error {
|
||||
handler := func(data *bindings.ReadResponse) error {
|
||||
s := string(data.Data)
|
||||
assert.Equal(t, s, "This is my message")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -231,9 +235,10 @@ func TestReadQueueNoMessage(t *testing.T) {
|
|||
err := a.Init(m)
|
||||
assert.Nil(t, err)
|
||||
|
||||
var handler = func(data *bindings.ReadResponse) error {
|
||||
handler := func(data *bindings.ReadResponse) error {
|
||||
s := string(data.Data)
|
||||
assert.Equal(t, s, "This is my message")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ func (b *Binding) Init(metadata bindings.Metadata) error {
|
|||
return errors.Wrapf(err, "invalid schedule format: %s", s)
|
||||
}
|
||||
b.schedule = s
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -73,6 +74,7 @@ func (b *Binding) Read(handler func(*bindings.ReadResponse) error) error {
|
|||
<-b.stopCh
|
||||
b.logger.Debugf("stopping schedule: %s", b.schedule)
|
||||
c.Stop()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -84,6 +86,7 @@ func (b *Binding) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeResponse,
|
|||
req.Operation, bindings.DeleteOperation)
|
||||
}
|
||||
b.stopCh <- true
|
||||
|
||||
return &bindings.InvokeResponse{
|
||||
Metadata: map[string]string{
|
||||
"schedule": b.schedule,
|
||||
|
|
|
@ -19,6 +19,7 @@ func getTestMetadata(schedule string) bindings.Metadata {
|
|||
m.Properties = map[string]string{
|
||||
"schedule": schedule,
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
|
@ -27,6 +28,7 @@ func getNewCron() *Binding {
|
|||
if os.Getenv("DEBUG") != "" {
|
||||
l.SetOutputLevel(logger.DebugLevel)
|
||||
}
|
||||
|
||||
return NewCron(l)
|
||||
}
|
||||
|
||||
|
@ -70,6 +72,7 @@ func TestCronReadWithDeleteInvoke(t *testing.T) {
|
|||
assert.Truef(t, exists, "Response metadata doesn't include the expected 'schedule' key")
|
||||
assert.Equal(t, schedule, scheduleVal)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
assert.NoErrorf(t, err, "error on read")
|
||||
|
|
|
@ -63,6 +63,7 @@ func (g *GCPStorage) Init(metadata bindings.Metadata) error {
|
|||
|
||||
g.metadata = gm
|
||||
g.client = client
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -71,6 +72,7 @@ func (g *GCPStorage) parseMetadata(metadata bindings.Metadata) ([]byte, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
|
@ -90,5 +92,6 @@ func (g *GCPStorage) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeRespon
|
|||
if _, err := h.Write(req.Data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -16,8 +16,10 @@ import (
|
|||
|
||||
func TestInit(t *testing.T) {
|
||||
m := bindings.Metadata{}
|
||||
m.Properties = map[string]string{"auth_provider_x509_cert_url": "a", "auth_uri": "a", "Bucket": "a", "client_x509_cert_url": "a", "client_email": "a", "client_id": "a", "private_key": "a",
|
||||
"private_key_id": "a", "project_id": "a", "token_uri": "a", "type": "a"}
|
||||
m.Properties = map[string]string{
|
||||
"auth_provider_x509_cert_url": "a", "auth_uri": "a", "Bucket": "a", "client_x509_cert_url": "a", "client_email": "a", "client_id": "a", "private_key": "a",
|
||||
"private_key_id": "a", "project_id": "a", "token_uri": "a", "type": "a",
|
||||
}
|
||||
gs := GCPStorage{logger: logger.NewLogger("test")}
|
||||
b, err := gs.parseMetadata(m)
|
||||
assert.Nil(t, err)
|
||||
|
|
|
@ -70,11 +70,13 @@ func (g *GCPPubSub) Init(metadata bindings.Metadata) error {
|
|||
|
||||
g.client = pubsubClient
|
||||
g.metadata = &pubsubMeta
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *GCPPubSub) parseMetadata(metadata bindings.Metadata) ([]byte, error) {
|
||||
b, err := json.Marshal(metadata.Properties)
|
||||
|
||||
return b, err
|
||||
}
|
||||
|
||||
|
@ -89,6 +91,7 @@ func (g *GCPPubSub) Read(handler func(*bindings.ReadResponse) error) error {
|
|||
m.Ack()
|
||||
}
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -107,5 +110,6 @@ func (g *GCPPubSub) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeRespons
|
|||
_, err := t.Publish(ctx, &pubsub.Message{
|
||||
Data: req.Data,
|
||||
}).Get(ctx)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -16,8 +16,10 @@ import (
|
|||
|
||||
func TestInit(t *testing.T) {
|
||||
m := bindings.Metadata{}
|
||||
m.Properties = map[string]string{"auth_provider_x509_cert_url": "https://auth", "auth_uri": "https://auth", "client_x509_cert_url": "https://cert", "client_email": "test@test.com", "client_id": "id", "private_key": "****",
|
||||
"private_key_id": "key_id", "project_id": "project1", "token_uri": "https://token", "type": "serviceaccount", "topic": "t1", "subscription": "s1"}
|
||||
m.Properties = map[string]string{
|
||||
"auth_provider_x509_cert_url": "https://auth", "auth_uri": "https://auth", "client_x509_cert_url": "https://cert", "client_email": "test@test.com", "client_id": "id", "private_key": "****",
|
||||
"private_key_id": "key_id", "project_id": "project1", "token_uri": "https://token", "type": "serviceaccount", "topic": "t1", "subscription": "s1",
|
||||
}
|
||||
ps := GCPPubSub{logger: logger.NewLogger("test")}
|
||||
b, err := ps.parseMetadata(m)
|
||||
assert.Nil(t, err)
|
||||
|
|
|
@ -48,11 +48,13 @@ func (h *HTTPSource) Init(metadata bindings.Metadata) error {
|
|||
}
|
||||
|
||||
h.metadata = m
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *HTTPSource) get(url string) ([]byte, error) {
|
||||
client := http.Client{Timeout: time.Second * 60}
|
||||
// nolint: noctx
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -66,6 +68,7 @@ func (h *HTTPSource) get(url string) ([]byte, error) {
|
|||
if resp != nil && resp.Body != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
|
@ -78,6 +81,7 @@ func (h *HTTPSource) Read(handler func(*bindings.ReadResponse) error) error {
|
|||
handler(&bindings.ReadResponse{
|
||||
Data: b,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -87,6 +91,7 @@ func (h *HTTPSource) Operations() []bindings.OperationKind {
|
|||
|
||||
func (h *HTTPSource) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
|
||||
client := http.Client{Timeout: time.Second * 5}
|
||||
// nolint: noctx
|
||||
resp, err := client.Post(h.metadata.URL, "application/json; charset=utf-8", bytes.NewBuffer(req.Data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -94,5 +99,6 @@ func (h *HTTPSource) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeRespon
|
|||
if resp != nil && resp.Body != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ func (i *Influx) Init(metadata bindings.Metadata) error {
|
|||
client := influxdb2.NewClient(i.metadata.URL, i.metadata.Token)
|
||||
i.client = client
|
||||
i.writeAPI = i.client.WriteAPIBlocking(i.metadata.Org, i.metadata.Bucket)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -79,6 +80,7 @@ func (i *Influx) getInfluxMetadata(metadata bindings.Metadata) (*influxMetadata,
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &iMetadata, nil
|
||||
}
|
||||
|
||||
|
@ -103,5 +105,6 @@ func (i *Influx) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeResponse,
|
|||
return nil, errors.New("Influx Error: Cannot write point")
|
||||
}
|
||||
i.client.Close()
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -64,11 +64,13 @@ func (consumer *consumer) ConsumeClaim(session sarama.ConsumerGroupSession, clai
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (consumer *consumer) Setup(sarama.ConsumerGroupSession) error {
|
||||
close(consumer.ready)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -96,11 +98,12 @@ func (k *Kafka) Init(metadata bindings.Metadata) error {
|
|||
k.consumerGroup = meta.ConsumerGroup
|
||||
k.authRequired = meta.AuthRequired
|
||||
|
||||
//ignore SASL properties if authRequired is false
|
||||
// ignore SASL properties if authRequired is false
|
||||
if meta.AuthRequired {
|
||||
k.saslUsername = meta.SaslUsername
|
||||
k.saslPassword = meta.SaslPassword
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -146,13 +149,12 @@ func (k *Kafka) getKafkaMetadata(metadata bindings.Metadata) (*kafkaMetadata, er
|
|||
return nil, errors.New("kafka error: 'authRequired' attribute was empty")
|
||||
}
|
||||
validAuthRequired, err := strconv.ParseBool(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.New("kafka error: invalid value for 'authRequired' attribute")
|
||||
}
|
||||
meta.AuthRequired = validAuthRequired
|
||||
|
||||
//ignore SASL properties if authRequired is false
|
||||
// ignore SASL properties if authRequired is false
|
||||
if meta.AuthRequired {
|
||||
if val, ok := metadata.Properties["saslUsername"]; ok && val != "" {
|
||||
meta.SaslUsername = val
|
||||
|
@ -166,6 +168,7 @@ func (k *Kafka) getKafkaMetadata(metadata bindings.Metadata) (*kafkaMetadata, er
|
|||
return nil, errors.New("kafka error: missing SASL Password")
|
||||
}
|
||||
}
|
||||
|
||||
return &meta, nil
|
||||
}
|
||||
|
||||
|
@ -176,7 +179,7 @@ func (k *Kafka) getSyncProducer(meta *kafkaMetadata) (sarama.SyncProducer, error
|
|||
config.Producer.Return.Successes = true
|
||||
config.Version = sarama.V1_0_0_0
|
||||
|
||||
//ignore SASL properties if authRequired is false
|
||||
// ignore SASL properties if authRequired is false
|
||||
if meta.AuthRequired {
|
||||
updateAuthInfo(config, meta.SaslUsername, meta.SaslPassword)
|
||||
}
|
||||
|
@ -185,13 +188,14 @@ func (k *Kafka) getSyncProducer(meta *kafkaMetadata) (sarama.SyncProducer, error
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return producer, nil
|
||||
}
|
||||
|
||||
func (k *Kafka) Read(handler func(*bindings.ReadResponse) error) error {
|
||||
config := sarama.NewConfig()
|
||||
config.Version = sarama.V1_0_0_0
|
||||
//ignore SASL properties if authRequired is false
|
||||
// ignore SASL properties if authRequired is false
|
||||
if k.authRequired {
|
||||
updateAuthInfo(config, k.saslUsername, k.saslPassword)
|
||||
}
|
||||
|
@ -233,12 +237,14 @@ func (k *Kafka) Read(handler func(*bindings.ReadResponse) error) error {
|
|||
if err = client.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (consumer *consumer) Cleanup(sarama.ConsumerGroupSession) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateAuthInfo(config *sarama.Config, saslUsername, saslPassword string) {
|
||||
config.Net.SASL.Enable = true
|
||||
config.Net.SASL.User = saslUsername
|
||||
|
@ -246,8 +252,9 @@ func updateAuthInfo(config *sarama.Config, saslUsername, saslPassword string) {
|
|||
config.Net.SASL.Mechanism = sarama.SASLTypePlaintext
|
||||
|
||||
config.Net.TLS.Enable = true
|
||||
// nolint: gosec
|
||||
config.Net.TLS.Config = &tls.Config{
|
||||
//InsecureSkipVerify: true,
|
||||
// InsecureSkipVerify: true,
|
||||
ClientAuth: 0,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ import (
|
|||
"time"
|
||||
|
||||
kubeclient "github.com/dapr/components-contrib/authentication/kubernetes"
|
||||
|
||||
"github.com/dapr/components-contrib/bindings"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
@ -50,6 +49,7 @@ func (k *kubernetesInput) Init(metadata bindings.Metadata) error {
|
|||
return err
|
||||
}
|
||||
k.kubeClient = client
|
||||
|
||||
return k.parseMetadata(metadata)
|
||||
}
|
||||
|
||||
|
@ -68,6 +68,7 @@ func (k *kubernetesInput) parseMetadata(metadata bindings.Metadata) error {
|
|||
k.resyncPeriodInSec = time.Second * time.Duration(intval)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -139,5 +140,6 @@ func (k *kubernetesInput) Read(handler func(*bindings.ReadResponse) error) error
|
|||
close(stopCh)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ import (
|
|||
|
||||
"github.com/dapr/components-contrib/bindings"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
|
||||
mqtt "github.com/eclipse/paho.mqtt.golang"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
@ -66,6 +65,7 @@ func (m *MQTT) Init(metadata bindings.Metadata) error {
|
|||
return err
|
||||
}
|
||||
m.client = client
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -80,6 +80,7 @@ func (m *MQTT) getMQTTMetadata(metadata bindings.Metadata) (*mqttMetadata, error
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &mMetadata, nil
|
||||
}
|
||||
|
||||
|
@ -90,6 +91,7 @@ func (m *MQTT) Operations() []bindings.OperationKind {
|
|||
func (m *MQTT) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
|
||||
m.client.Publish(m.metadata.Topic, 0, false, string(req.Data))
|
||||
m.client.Disconnect(0)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
@ -103,6 +105,7 @@ func (m *MQTT) Read(handler func(*bindings.ReadResponse) error) error {
|
|||
})
|
||||
})
|
||||
<-c
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -115,6 +118,7 @@ func (m *MQTT) connect(clientID string, uri *url.URL) (mqtt.Client, error) {
|
|||
if err := token.Error(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
|
@ -125,5 +129,6 @@ func (m *MQTT) createClientOptions(clientID string, uri *url.URL) *mqtt.ClientOp
|
|||
password, _ := uri.User.Password()
|
||||
opts.SetPassword(password)
|
||||
opts.SetClientID(clientID)
|
||||
|
||||
return opts
|
||||
}
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/dapr/components-contrib/bindings"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// List of operations.
|
||||
const (
|
||||
execOperation bindings.OperationKind = "exec"
|
||||
queryOperation bindings.OperationKind = "query"
|
||||
closeOperation bindings.OperationKind = "close"
|
||||
|
||||
connectionURLKey = "url"
|
||||
commandSQLKey = "sql"
|
||||
)
|
||||
|
||||
// Postgres represents PostgreSQL output binding
|
||||
type Postgres struct {
|
||||
logger logger.Logger
|
||||
db *pgxpool.Pool
|
||||
}
|
||||
|
||||
var _ = bindings.OutputBinding(&Postgres{})
|
||||
|
||||
// NewPostgres returns a new PostgreSQL output binding
|
||||
func NewPostgres(logger logger.Logger) *Postgres {
|
||||
return &Postgres{logger: logger}
|
||||
}
|
||||
|
||||
// Init initializes the PostgreSql binding
|
||||
func (p *Postgres) Init(metadata bindings.Metadata) error {
|
||||
url, ok := metadata.Properties[connectionURLKey]
|
||||
if !ok || url == "" {
|
||||
return errors.Errorf("required metadata not set: %s", connectionURLKey)
|
||||
}
|
||||
|
||||
poolConfig, err := pgxpool.ParseConfig(url)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error opening DB connection")
|
||||
}
|
||||
|
||||
p.db, err = pgxpool.ConnectConfig(context.Background(), poolConfig)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to ping the DB")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Operations returns list of operations supported by PostgreSql binding
|
||||
func (p *Postgres) Operations() []bindings.OperationKind {
|
||||
return []bindings.OperationKind{
|
||||
execOperation,
|
||||
queryOperation,
|
||||
closeOperation,
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke handles all invoke operations
|
||||
func (p *Postgres) Invoke(req *bindings.InvokeRequest) (resp *bindings.InvokeResponse, err error) {
|
||||
if req == nil {
|
||||
return nil, errors.Errorf("invoke request required")
|
||||
}
|
||||
|
||||
if req.Operation == closeOperation {
|
||||
p.db.Close()
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if req.Metadata == nil {
|
||||
return nil, errors.Errorf("metadata required")
|
||||
}
|
||||
p.logger.Debugf("operation: %v", req.Operation)
|
||||
|
||||
sql, ok := req.Metadata[commandSQLKey]
|
||||
if !ok || sql == "" {
|
||||
return nil, errors.Errorf("required metadata not set: %s", commandSQLKey)
|
||||
}
|
||||
|
||||
startTime := time.Now().UTC()
|
||||
resp = &bindings.InvokeResponse{
|
||||
Metadata: map[string]string{
|
||||
"operation": string(req.Operation),
|
||||
"sql": sql,
|
||||
"start-time": startTime.Format(time.RFC3339Nano),
|
||||
},
|
||||
}
|
||||
|
||||
switch req.Operation { // nolint: exhaustive
|
||||
case execOperation:
|
||||
r, err := p.exec(sql)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error executing %s with %v", sql, err)
|
||||
}
|
||||
resp.Metadata["rows-affected"] = strconv.FormatInt(r, 10) // 0 if error
|
||||
|
||||
case queryOperation:
|
||||
d, err := p.query(sql)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error executing %s with %v", sql, err)
|
||||
}
|
||||
resp.Data = d
|
||||
|
||||
default:
|
||||
return nil, errors.Errorf(
|
||||
"invalid operation type: %s. Expected %s, %s, or %s",
|
||||
req.Operation, execOperation, queryOperation, closeOperation,
|
||||
)
|
||||
}
|
||||
|
||||
endTime := time.Now().UTC()
|
||||
resp.Metadata["end-time"] = endTime.Format(time.RFC3339Nano)
|
||||
resp.Metadata["duration"] = endTime.Sub(startTime).String()
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (p *Postgres) query(sql string) (result []byte, err error) {
|
||||
p.logger.Debugf("query: %s", sql)
|
||||
|
||||
rows, err := p.db.Query(context.Background(), sql)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error executing %s", sql)
|
||||
}
|
||||
|
||||
rs := make([]interface{}, 0)
|
||||
for rows.Next() {
|
||||
val, rowErr := rows.Values()
|
||||
if rowErr != nil {
|
||||
return nil, errors.Wrapf(rowErr, "error parsing result: %v", rows.Err())
|
||||
}
|
||||
rs = append(rs, val)
|
||||
}
|
||||
|
||||
if result, err = json.Marshal(rs); err != nil {
|
||||
err = errors.Wrap(err, "error serializing results")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Postgres) exec(sql string) (result int64, err error) {
|
||||
p.logger.Debugf("exec: %s", sql)
|
||||
|
||||
res, err := p.db.Exec(context.Background(), sql)
|
||||
if err != nil {
|
||||
return 0, errors.Wrapf(err, "error executing %s", sql)
|
||||
}
|
||||
|
||||
result = res.RowsAffected()
|
||||
|
||||
return
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/dapr/components-contrib/bindings"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const (
|
||||
testTableDDL = `CREATE TABLE IF NOT EXISTS foo (
|
||||
id bigint NOT NULL,
|
||||
v1 character varying(50) NOT NULL,
|
||||
ts TIMESTAMP)`
|
||||
testInsert = "INSERT INTO foo (id, v1, ts) VALUES (%d, 'test-%d', '%v')"
|
||||
testDelete = "DELETE FROM foo"
|
||||
testUpdate = "UPDATE foo SET ts = '%v' WHERE id = %d"
|
||||
testSelect = "SELECT * FROM foo WHERE id < 3"
|
||||
)
|
||||
|
||||
func TestOperations(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("Get operation list", func(t *testing.T) {
|
||||
b := NewPostgres(nil)
|
||||
assert.NotNil(t, b)
|
||||
l := b.Operations()
|
||||
assert.Equal(t, 3, len(l))
|
||||
})
|
||||
}
|
||||
|
||||
// SETUP TESTS
|
||||
// 1. `createdb daprtest`
|
||||
// 2. `createuser daprtest`
|
||||
// 3. `psql=# grant all privileges on database daprtest to daprtest;``
|
||||
// 4. `export POSTGRES_TEST_CONN_URL="postgres://daprtest@localhost:5432/daprtest"``
|
||||
// 5. `go test -v -count=1 ./bindings/postgres -run ^TestPostgresIntegration`
|
||||
|
||||
func TestPostgresIntegration(t *testing.T) {
|
||||
url := os.Getenv("POSTGRES_TEST_CONN_URL")
|
||||
if url == "" {
|
||||
t.SkipNow()
|
||||
}
|
||||
|
||||
// live DB test
|
||||
b := NewPostgres(logger.NewLogger("test"))
|
||||
m := bindings.Metadata{Properties: map[string]string{connectionURLKey: url}}
|
||||
if err := b.Init(m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// create table
|
||||
req := &bindings.InvokeRequest{
|
||||
Operation: execOperation,
|
||||
Metadata: map[string]string{commandSQLKey: testTableDDL},
|
||||
}
|
||||
|
||||
t.Run("Invoke create table", func(t *testing.T) {
|
||||
res, err := b.Invoke(req)
|
||||
assertResponse(t, res, err)
|
||||
})
|
||||
|
||||
t.Run("Invoke delete", func(t *testing.T) {
|
||||
req.Metadata[commandSQLKey] = testDelete
|
||||
res, err := b.Invoke(req)
|
||||
assertResponse(t, res, err)
|
||||
})
|
||||
|
||||
t.Run("Invoke insert", func(t *testing.T) {
|
||||
for i := 0; i < 10; i++ {
|
||||
req.Metadata[commandSQLKey] = fmt.Sprintf(testInsert, i, i, time.Now().Format(time.RFC3339))
|
||||
res, err := b.Invoke(req)
|
||||
assertResponse(t, res, err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Invoke update", func(t *testing.T) {
|
||||
for i := 0; i < 10; i++ {
|
||||
req.Metadata[commandSQLKey] = fmt.Sprintf(testUpdate, time.Now().Format(time.RFC3339), i)
|
||||
res, err := b.Invoke(req)
|
||||
assertResponse(t, res, err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Invoke select", func(t *testing.T) {
|
||||
req.Operation = queryOperation
|
||||
req.Metadata[commandSQLKey] = testSelect
|
||||
res, err := b.Invoke(req)
|
||||
assertResponse(t, res, err)
|
||||
})
|
||||
|
||||
t.Run("Invoke delete", func(t *testing.T) {
|
||||
req.Operation = execOperation
|
||||
req.Metadata[commandSQLKey] = testDelete
|
||||
req.Data = nil
|
||||
res, err := b.Invoke(req)
|
||||
assertResponse(t, res, err)
|
||||
})
|
||||
|
||||
t.Run("Invoke close", func(t *testing.T) {
|
||||
req.Operation = closeOperation
|
||||
req.Metadata = nil
|
||||
req.Data = nil
|
||||
_, err := b.Invoke(req)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func assertResponse(t *testing.T, res *bindings.InvokeResponse, err error) {
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, res)
|
||||
assert.NotNil(t, res.Metadata)
|
||||
}
|
|
@ -6,7 +6,8 @@
|
|||
package rabbitmq
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
|
@ -16,7 +17,14 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
host = "host"
|
||||
queueName = "queueName"
|
||||
durable = "durable"
|
||||
deleteWhenUnused = "deleteWhenUnused"
|
||||
prefetchCount = "prefetchCount"
|
||||
rabbitMQQueueMessageTTLKey = "x-message-ttl"
|
||||
defaultBase = 10
|
||||
defaultBitSize = 0
|
||||
)
|
||||
|
||||
// RabbitMQ allows sending/receiving data to/from RabbitMQ
|
||||
|
@ -30,10 +38,11 @@ type RabbitMQ struct {
|
|||
|
||||
// Metadata is the rabbitmq config
|
||||
type rabbitMQMetadata struct {
|
||||
QueueName string `json:"queueName"`
|
||||
Host string `json:"host"`
|
||||
QueueName string `json:"queueName"`
|
||||
Durable bool `json:"durable,string"`
|
||||
DeleteWhenUnused bool `json:"deleteWhenUnused,string"`
|
||||
PrefetchCount int `json:"prefetchCount"`
|
||||
defaultQueueTTL *time.Duration
|
||||
}
|
||||
|
||||
|
@ -58,7 +67,7 @@ func (r *RabbitMQ) Init(metadata bindings.Metadata) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ch.Qos(r.metadata.PrefetchCount, 0, true)
|
||||
r.connection = conn
|
||||
r.channel = ch
|
||||
|
||||
|
@ -105,15 +114,42 @@ func (r *RabbitMQ) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeResponse
|
|||
}
|
||||
|
||||
func (r *RabbitMQ) parseMetadata(metadata bindings.Metadata) error {
|
||||
b, err := json.Marshal(metadata.Properties)
|
||||
if err != nil {
|
||||
return err
|
||||
m := rabbitMQMetadata{}
|
||||
|
||||
if val, ok := metadata.Properties[host]; ok && val != "" {
|
||||
m.Host = val
|
||||
} else {
|
||||
return errors.New("rabbitMQ binding error: missing host address")
|
||||
}
|
||||
|
||||
var m rabbitMQMetadata
|
||||
err = json.Unmarshal(b, &m)
|
||||
if err != nil {
|
||||
return err
|
||||
if val, ok := metadata.Properties[queueName]; ok && val != "" {
|
||||
m.QueueName = val
|
||||
} else {
|
||||
return errors.New("rabbitMQ binding error: missing queue Name")
|
||||
}
|
||||
|
||||
if val, ok := metadata.Properties[durable]; ok && val != "" {
|
||||
d, err := strconv.ParseBool(val)
|
||||
if err != nil {
|
||||
return fmt.Errorf("rabbitMQ binding error: can't parse durable field: %s", err)
|
||||
}
|
||||
m.Durable = d
|
||||
}
|
||||
|
||||
if val, ok := metadata.Properties[deleteWhenUnused]; ok && val != "" {
|
||||
d, err := strconv.ParseBool(val)
|
||||
if err != nil {
|
||||
return fmt.Errorf("rabbitMQ binding error: can't parse deleteWhenUnused field: %s", err)
|
||||
}
|
||||
m.DeleteWhenUnused = d
|
||||
}
|
||||
|
||||
if val, ok := metadata.Properties[prefetchCount]; ok && val != "" {
|
||||
parsedVal, err := strconv.ParseInt(val, defaultBase, defaultBitSize)
|
||||
if err != nil {
|
||||
return fmt.Errorf("rabbitMQ binding error: can't parse prefetchCount field: %s", err)
|
||||
}
|
||||
m.PrefetchCount = int(parsedVal)
|
||||
}
|
||||
|
||||
ttl, ok, err := bindings.TryGetTTL(metadata.Properties)
|
||||
|
@ -126,6 +162,7 @@ func (r *RabbitMQ) parseMetadata(metadata bindings.Metadata) error {
|
|||
}
|
||||
|
||||
r.metadata = m
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -168,5 +205,6 @@ func (r *RabbitMQ) Read(handler func(*bindings.ReadResponse) error) error {
|
|||
}()
|
||||
|
||||
<-forever
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -25,32 +25,40 @@ func TestParseMetadata(t *testing.T) {
|
|||
expectedDeleteWhenUnused bool
|
||||
expectedDurable bool
|
||||
expectedTTL *time.Duration
|
||||
expectedPrefetchCount int
|
||||
}{
|
||||
{
|
||||
name: "Delete / Durable",
|
||||
properties: map[string]string{"QueueName": queueName, "Host": host, "DeleteWhenUnused": "true", "Durable": "true"},
|
||||
properties: map[string]string{"queueName": queueName, "host": host, "deleteWhenUnused": "true", "durable": "true"},
|
||||
expectedDeleteWhenUnused: true,
|
||||
expectedDurable: true,
|
||||
},
|
||||
{
|
||||
name: "Not Delete / Not Durable",
|
||||
properties: map[string]string{"QueueName": queueName, "Host": host, "DeleteWhenUnused": "false", "Durable": "false"},
|
||||
name: "Not Delete / Not durable",
|
||||
properties: map[string]string{"queueName": queueName, "host": host, "deleteWhenUnused": "false", "durable": "false"},
|
||||
expectedDeleteWhenUnused: false,
|
||||
expectedDurable: false,
|
||||
},
|
||||
{
|
||||
name: "With one second TTL",
|
||||
properties: map[string]string{"QueueName": queueName, "Host": host, "DeleteWhenUnused": "false", "Durable": "false", bindings.TTLMetadataKey: "1"},
|
||||
properties: map[string]string{"queueName": queueName, "host": host, "deleteWhenUnused": "false", "durable": "false", bindings.TTLMetadataKey: "1"},
|
||||
expectedDeleteWhenUnused: false,
|
||||
expectedDurable: false,
|
||||
expectedTTL: &oneSecondTTL,
|
||||
},
|
||||
{
|
||||
name: "Empty TTL",
|
||||
properties: map[string]string{"QueueName": queueName, "Host": host, "DeleteWhenUnused": "false", "Durable": "false", bindings.TTLMetadataKey: ""},
|
||||
properties: map[string]string{"queueName": queueName, "host": host, "deleteWhenUnused": "false", "durable": "false", bindings.TTLMetadataKey: ""},
|
||||
expectedDeleteWhenUnused: false,
|
||||
expectedDurable: false,
|
||||
},
|
||||
{
|
||||
name: "With one prefetchCount",
|
||||
properties: map[string]string{"queueName": queueName, "host": host, "deleteWhenUnused": "false", "durable": "false", "prefetchCount": "1"},
|
||||
expectedDeleteWhenUnused: false,
|
||||
expectedDurable: false,
|
||||
expectedPrefetchCount: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range testCases {
|
||||
|
@ -65,6 +73,7 @@ func TestParseMetadata(t *testing.T) {
|
|||
assert.Equal(t, tt.expectedDeleteWhenUnused, r.metadata.DeleteWhenUnused)
|
||||
assert.Equal(t, tt.expectedDurable, r.metadata.Durable)
|
||||
assert.Equal(t, tt.expectedTTL, r.metadata.defaultQueueTTL)
|
||||
assert.Equal(t, tt.expectedPrefetchCount, r.metadata.PrefetchCount)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -79,15 +88,15 @@ func TestParseMetadataWithInvalidTTL(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
name: "Whitespaces TTL",
|
||||
properties: map[string]string{"QueueName": queueName, "Host": host, bindings.TTLMetadataKey: " "},
|
||||
properties: map[string]string{"queueName": queueName, "host": host, bindings.TTLMetadataKey: " "},
|
||||
},
|
||||
{
|
||||
name: "Negative ttl",
|
||||
properties: map[string]string{"QueueName": queueName, "Host": host, bindings.TTLMetadataKey: "-1"},
|
||||
properties: map[string]string{"queueName": queueName, "host": host, bindings.TTLMetadataKey: "-1"},
|
||||
},
|
||||
{
|
||||
name: "Non-numeric ttl",
|
||||
properties: map[string]string{"QueueName": queueName, "Host": host, bindings.TTLMetadataKey: "abc"},
|
||||
properties: map[string]string{"queueName": queueName, "host": host, bindings.TTLMetadataKey: "abc"},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ import (
|
|||
|
||||
"github.com/dapr/components-contrib/bindings"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
|
||||
redis "github.com/go-redis/redis/v7"
|
||||
)
|
||||
|
||||
|
@ -129,7 +128,9 @@ func (r *Redis) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeResponse, e
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("redis binding: missing key on write request metadata")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
package statechange
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
r "github.com/dancannon/gorethink"
|
||||
"github.com/dapr/components-contrib/bindings"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Binding represents RethinkDB change change state input binding which fires handler with
|
||||
// both the previous and current state store content each time there is a change.
|
||||
type Binding struct {
|
||||
logger logger.Logger
|
||||
session *r.Session
|
||||
config StateConfig
|
||||
stopCh chan bool
|
||||
}
|
||||
|
||||
// StateConfig is the binding config
|
||||
type StateConfig struct {
|
||||
r.ConnectOpts
|
||||
Table string `json:"table"`
|
||||
}
|
||||
|
||||
var _ = bindings.InputBinding(&Binding{})
|
||||
|
||||
// NewRethinkDBStateChangeBinding returns a new RethinkDB actor event input binding
|
||||
func NewRethinkDBStateChangeBinding(logger logger.Logger) *Binding {
|
||||
return &Binding{
|
||||
logger: logger,
|
||||
stopCh: make(chan bool),
|
||||
}
|
||||
}
|
||||
|
||||
// Init initializes the RethinkDB binding
|
||||
func (b *Binding) Init(metadata bindings.Metadata) error {
|
||||
cfg, err := metadataToConfig(metadata.Properties, b.logger)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to parse metadata properties")
|
||||
}
|
||||
b.config = cfg
|
||||
|
||||
ses, err := r.Connect(b.config.ConnectOpts)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error connecting to the database")
|
||||
}
|
||||
b.session = ses
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read triggers the RethinkDB scheduler
|
||||
func (b *Binding) Read(handler func(*bindings.ReadResponse) error) error {
|
||||
b.logger.Infof("subscribing to state changes in %s.%s...", b.config.Database, b.config.Table)
|
||||
cursor, err := r.DB(b.config.Database).Table(b.config.Table).Changes(r.ChangesOpts{
|
||||
IncludeTypes: true,
|
||||
}).Run(b.session)
|
||||
if err != nil {
|
||||
errors.Wrapf(err, "error connecting to table %s", b.config.Table)
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
var change interface{}
|
||||
ok := cursor.Next(&change)
|
||||
if !ok {
|
||||
b.logger.Errorf("error detecting change: %v", cursor.Err())
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
data, err := json.Marshal(change)
|
||||
if err != nil {
|
||||
b.logger.Errorf("error marshalling change handler: %v", err)
|
||||
}
|
||||
b.logger.Debugf("event: %s", string(data))
|
||||
|
||||
resp := &bindings.ReadResponse{
|
||||
Data: data,
|
||||
Metadata: map[string]string{
|
||||
"store-address": b.config.Address,
|
||||
"store-database": b.config.Database,
|
||||
"store-table": b.config.Table,
|
||||
},
|
||||
}
|
||||
|
||||
if err := handler(resp); err != nil {
|
||||
b.logger.Errorf("error invoking change handler: %v", err)
|
||||
|
||||
continue
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
done := <-b.stopCh
|
||||
b.logger.Errorf("done: %b", done)
|
||||
defer cursor.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func metadataToConfig(cfg map[string]string, logger logger.Logger) (StateConfig, error) {
|
||||
c := StateConfig{}
|
||||
for k, v := range cfg {
|
||||
switch k {
|
||||
case "address": // string
|
||||
c.Address = v
|
||||
case "addresses": // []string
|
||||
c.Addresses = strings.Split(v, ",")
|
||||
case "database": // string
|
||||
c.Database = v
|
||||
case "username": // string
|
||||
c.Username = v
|
||||
case "password": // string
|
||||
c.Password = v
|
||||
case "authkey": // string
|
||||
c.AuthKey = v
|
||||
case "table": // string
|
||||
c.Table = v
|
||||
case "timeout": // time.Duration
|
||||
d, err := time.ParseDuration(v)
|
||||
if err != nil {
|
||||
return c, errors.Wrapf(err, "invalid timeout format: %v", v)
|
||||
}
|
||||
c.Timeout = d
|
||||
case "write_timeout": // time.Duration
|
||||
d, err := time.ParseDuration(v)
|
||||
if err != nil {
|
||||
return c, errors.Wrapf(err, "invalid write timeout format: %v", v)
|
||||
}
|
||||
c.WriteTimeout = d
|
||||
case "read_timeout": // time.Duration
|
||||
d, err := time.ParseDuration(v)
|
||||
if err != nil {
|
||||
return c, errors.Wrapf(err, "invalid read timeout format: %v", v)
|
||||
}
|
||||
c.ReadTimeout = d
|
||||
case "keep_alive_timeout": // time.Duration
|
||||
d, err := time.ParseDuration(v)
|
||||
if err != nil {
|
||||
return c, errors.Wrapf(err, "invalid keep alive timeout format: %v", v)
|
||||
}
|
||||
c.KeepAlivePeriod = d
|
||||
case "initial_cap": // int
|
||||
i, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return c, errors.Wrapf(err, "invalid keep initial cap format: %v", v)
|
||||
}
|
||||
c.InitialCap = i
|
||||
case "max_open": // int
|
||||
i, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return c, errors.Wrapf(err, "invalid keep max open format: %v", v)
|
||||
}
|
||||
c.MaxOpen = i
|
||||
case "discover_hosts": // bool
|
||||
b, err := strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
return c, errors.Wrapf(err, "invalid discover hosts format: %v", v)
|
||||
}
|
||||
c.DiscoverHosts = b
|
||||
case "use-open-tracing": // bool
|
||||
b, err := strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
return c, errors.Wrapf(err, "invalid use open tracing format: %v", v)
|
||||
}
|
||||
c.UseOpentracing = b
|
||||
case "max_idle": // int
|
||||
i, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return c, errors.Wrapf(err, "invalid keep max idle format: %v", v)
|
||||
}
|
||||
c.InitialCap = i
|
||||
default:
|
||||
logger.Infof("unrecognized metadata: %s", k)
|
||||
}
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
package statechange
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/dapr/components-contrib/bindings"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func getTestMetadata() map[string]string {
|
||||
return map[string]string{
|
||||
"address": "127.0.0.1:28015",
|
||||
"database": "dapr",
|
||||
"username": "admin",
|
||||
"password": "rethinkdb",
|
||||
"table": "daprstate",
|
||||
}
|
||||
}
|
||||
|
||||
func getNewRethinkActorBinding() *Binding {
|
||||
l := logger.NewLogger("test")
|
||||
if os.Getenv("DEBUG") != "" {
|
||||
l.SetOutputLevel(logger.DebugLevel)
|
||||
}
|
||||
|
||||
return NewRethinkDBStateChangeBinding(l)
|
||||
}
|
||||
|
||||
/*
|
||||
go test github.com/dapr/components-contrib/bindings/rethinkdb/statechange \
|
||||
-run ^TestBinding$ -count 1
|
||||
*/
|
||||
|
||||
func TestBinding(t *testing.T) {
|
||||
if os.Getenv("RUN_LIVE_RETHINKDB_TEST") != "true" {
|
||||
t.SkipNow()
|
||||
}
|
||||
testDuration := 10 * time.Second
|
||||
testDurationStr := os.Getenv("RETHINKDB_TEST_DURATION")
|
||||
if testDurationStr != "" {
|
||||
d, err := time.ParseDuration(testDurationStr)
|
||||
if err != nil {
|
||||
t.Fatalf("invalid test duration: %s, expected time.Duration", testDurationStr)
|
||||
}
|
||||
testDuration = d
|
||||
}
|
||||
|
||||
m := bindings.Metadata{
|
||||
Name: "test",
|
||||
Properties: getTestMetadata(),
|
||||
}
|
||||
assert.NotNil(t, m.Properties)
|
||||
|
||||
b := getNewRethinkActorBinding()
|
||||
err := b.Init(m)
|
||||
assert.NoErrorf(t, err, "error initializing")
|
||||
|
||||
go func() {
|
||||
err = b.Read(func(res *bindings.ReadResponse) error {
|
||||
assert.NotNil(t, res)
|
||||
t.Logf("state change event:\n%s", string(res.Data))
|
||||
|
||||
return nil
|
||||
})
|
||||
assert.NoErrorf(t, err, "error on read")
|
||||
}()
|
||||
|
||||
testTimer := time.AfterFunc(testDuration, func() {
|
||||
t.Log("done")
|
||||
b.stopCh <- true
|
||||
})
|
||||
defer testTimer.Stop()
|
||||
<-b.stopCh
|
||||
}
|
|
@ -79,6 +79,7 @@ func (sg *SendGrid) Init(metadata bindings.Metadata) error {
|
|||
|
||||
// Um, yeah that's about it!
|
||||
sg.metadata = meta
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -182,5 +183,6 @@ func (sg *SendGrid) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeRespons
|
|||
}
|
||||
|
||||
sg.logger.Info("sent email with SendGrid")
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package sms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
@ -96,7 +97,7 @@ func (t *SMS) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeResponse, err
|
|||
vDr := *strings.NewReader(v.Encode())
|
||||
|
||||
twilioURL := fmt.Sprintf("%s%s/Messages.json", twilioURLBase, t.metadata.accountSid)
|
||||
httpReq, err := http.NewRequest("POST", twilioURL, &vDr)
|
||||
httpReq, err := http.NewRequestWithContext(context.Background(), "POST", twilioURL, &vDr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -112,5 +113,6 @@ func (t *SMS) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeResponse, err
|
|||
if !(resp.StatusCode >= 200 && resp.StatusCode < 300) {
|
||||
return nil, fmt.Errorf("error from Twilio: %s", resp.Status)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ func (t *mockTransport) reset() {
|
|||
func (t *mockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
atomic.AddInt32(&t.requestCount, 1)
|
||||
t.request = req
|
||||
|
||||
return t.response, t.errToReturn
|
||||
}
|
||||
|
||||
|
@ -46,8 +47,10 @@ func TestInit(t *testing.T) {
|
|||
|
||||
func TestParseDuration(t *testing.T) {
|
||||
m := bindings.Metadata{}
|
||||
m.Properties = map[string]string{"toNumber": "toNumber", "fromNumber": "fromNumber",
|
||||
"accountSid": "accountSid", "authToken": "authToken", "timeout": "badtimeout"}
|
||||
m.Properties = map[string]string{
|
||||
"toNumber": "toNumber", "fromNumber": "fromNumber",
|
||||
"accountSid": "accountSid", "authToken": "authToken", "timeout": "badtimeout",
|
||||
}
|
||||
tw := NewSMS(logger.NewLogger("test"))
|
||||
err := tw.Init(m)
|
||||
assert.NotNil(t, err)
|
||||
|
@ -58,8 +61,10 @@ func TestWriteShouldSucceed(t *testing.T) {
|
|||
response: &http.Response{StatusCode: 200, Body: ioutil.NopCloser(strings.NewReader(""))},
|
||||
}
|
||||
m := bindings.Metadata{}
|
||||
m.Properties = map[string]string{"toNumber": "toNumber", "fromNumber": "fromNumber",
|
||||
"accountSid": "accountSid", "authToken": "authToken"}
|
||||
m.Properties = map[string]string{
|
||||
"toNumber": "toNumber", "fromNumber": "fromNumber",
|
||||
"accountSid": "accountSid", "authToken": "authToken",
|
||||
}
|
||||
tw := NewSMS(logger.NewLogger("test"))
|
||||
tw.httpClient = &http.Client{
|
||||
Transport: httpTransport,
|
||||
|
@ -93,8 +98,10 @@ func TestWriteShouldFail(t *testing.T) {
|
|||
response: &http.Response{StatusCode: 200, Body: ioutil.NopCloser(strings.NewReader(""))},
|
||||
}
|
||||
m := bindings.Metadata{}
|
||||
m.Properties = map[string]string{"fromNumber": "fromNumber",
|
||||
"accountSid": "accountSid", "authToken": "authToken"}
|
||||
m.Properties = map[string]string{
|
||||
"fromNumber": "fromNumber",
|
||||
"accountSid": "accountSid", "authToken": "authToken",
|
||||
}
|
||||
tw := NewSMS(logger.NewLogger("test"))
|
||||
tw.httpClient = &http.Client{
|
||||
Transport: httpTransport,
|
||||
|
|
|
@ -16,10 +16,9 @@ import (
|
|||
|
||||
"github.com/dapr/components-contrib/bindings"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/dghubble/go-twitter/twitter"
|
||||
"github.com/dghubble/oauth1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Binding represents Twitter input/output binding
|
||||
|
@ -67,6 +66,7 @@ func (t *Binding) Init(metadata bindings.Metadata) error {
|
|||
httpClient := config.Client(oauth1.NoContext, token)
|
||||
|
||||
t.client = twitter.NewClient(httpClient)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,7 @@ func (t *Binding) Read(handler func(*bindings.ReadResponse) error) error {
|
|||
data, marshalErr := json.Marshal(tweet)
|
||||
if marshalErr != nil {
|
||||
t.logger.Errorf("error marshaling tweet: %+v", tweet)
|
||||
|
||||
return
|
||||
}
|
||||
handler(&bindings.ReadResponse{
|
||||
|
@ -139,6 +140,7 @@ func (t *Binding) Read(handler func(*bindings.ReadResponse) error) error {
|
|||
done = true
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -199,6 +201,7 @@ func (t *Binding) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeResponse,
|
|||
data, marshalErr := json.Marshal(search.Statuses)
|
||||
if marshalErr != nil {
|
||||
t.logger.Errorf("error marshaling tweet: %v", marshalErr)
|
||||
|
||||
return nil, errors.Wrapf(err, "error parsing response from: %+v", sq)
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ func getTestMetadata() bindings.Metadata {
|
|||
"accessToken": testTwitterAccessToken,
|
||||
"accessSecret": testTwitterAccessSecret,
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
|
@ -62,6 +63,7 @@ func TestReadError(t *testing.T) {
|
|||
tw.Read(func(res *bindings.ReadResponse) error {
|
||||
t.Logf("result: %+v", res)
|
||||
assert.NotNilf(t, err, "no error on read with invalid credentials")
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
@ -89,6 +91,7 @@ func TestReed(t *testing.T) {
|
|||
json.Unmarshal(res.Data, &tweet)
|
||||
assert.NotEmpty(t, tweet.IDStr, "tweet should have an ID")
|
||||
os.Exit(0)
|
||||
|
||||
return nil
|
||||
})
|
||||
assert.Nilf(t, err, "error on read")
|
||||
|
|
|
@ -31,13 +31,13 @@ git clone https://github.com/dapr/components-contrib.git github.com/dapr/compone
|
|||
|
||||
| Type | Directory | Reference | Docs |
|
||||
|------|-----------|--------------------------|------|
|
||||
| State | [components-contrib/state](https://github.com/dapr/components-contrib/tree/master/state) | [Redis](https://github.com/dapr/components-contrib/tree/master/state/redis) | [concept](https://github.com/dapr/docs/blob/master/concepts/state-management), [howto](https://github.com/dapr/docs/tree/master/howto/setup-state-store), [api spec](https://github.com/dapr/docs/blob/master/reference/api/state_api.md) |
|
||||
| Pubsub | [components-contrib/pubsub](https://github.com/dapr/components-contrib/tree/master/pubsub) | [Redis](https://github.com/dapr/components-contrib/tree/master/pubsub/redis) | [concept](https://github.com/dapr/docs/tree/master/concepts/publish-subscribe-messaging), [howto](https://github.com/dapr/docs/tree/master/howto/setup-pub-sub-message-broker), [api spec](https://github.com/dapr/docs/blob/master/reference/api/pubsub_api.md) |
|
||||
| Bindings | [components-contrib/bindings](https://github.com/dapr/components-contrib/tree/master/bindings) | [Kafka](https://github.com/dapr/components-contrib/tree/master/bindings/kafka) | [concept](https://github.com/dapr/docs/tree/master/concepts/bindings), [input howto](https://github.com/dapr/docs/tree/master/howto/trigger-app-with-input-binding), [output howto](https://github.com/dapr/docs/tree/master/howto/send-events-with-output-bindings), [api spec](https://github.com/dapr/docs/blob/master/reference/api/bindings_api.md) |
|
||||
| Secret Store | [components-contrib/secretstore](https://github.com/dapr/components-contrib/tree/master/secretstores) | [Kubernetes](https://github.com/dapr/components-contrib/tree/master/secretstores/kubernetes), [Azure Keyvault](https://github.com/dapr/components-contrib/tree/master/secretstores/azure/keyvault) | [concept](https://github.com/dapr/docs/blob/master/concepts/secrets), [howto](https://github.com/dapr/docs/tree/master/howto/setup-secret-store)|
|
||||
| Middleware | [components-contrib/middleware](https://github.com/dapr/components-contrib/tree/master/middleware) | [Oauth2](https://github.com/dapr/components-contrib/blob/master/middleware/http/oauth2/oauth2_middleware.go) | [concept](https://github.com/dapr/docs/blob/master/concepts/middleware), [howto](https://github.com/dapr/docs/tree/master/howto/authorization-with-oauth) |
|
||||
| Exporter | [components-contrib/exporters](https://github.com/dapr/components-contrib/tree/master/exporters) | [Zipkin](https://github.com/dapr/components-contrib/blob/master/exporters/zipkin/zipkin_exporter.go) | [concept](https://github.com/dapr/docs/tree/master/concepts/observability), [howto](https://github.com/dapr/docs/tree/master/howto/diagnose-with-tracing) |
|
||||
| Service Discovery | [components-contrib/servicediscovery](https://github.com/dapr/components-contrib/tree/master/servicediscovery) | [mdns](https://github.com/dapr/components-contrib/blob/master/servicediscovery/mdns/mdns.go) | [howto](https://github.com/dapr/docs/tree/master/howto/invoke-and-discover-services) |
|
||||
| State | [components-contrib/state](https://github.com/dapr/components-contrib/tree/master/state) | [Redis](https://github.com/dapr/components-contrib/tree/master/state/redis) | [concept](https://docs.dapr.io/developing-applications/building-blocks/state-management/state-management-overview/), [howto](https://docs.dapr.io/developing-applications/building-blocks/state-management/howto-get-save-state/), [api spec](https://docs.dapr.io/reference/api/state_api/) |
|
||||
| Pubsub | [components-contrib/pubsub](https://github.com/dapr/components-contrib/tree/master/pubsub) | [Redis](https://github.com/dapr/components-contrib/tree/master/pubsub/redis) | [concept](https://docs.dapr.io/developing-applications/building-blocks/pubsub/pubsub-overview/), [howto](https://docs.dapr.io/developing-applications/building-blocks/pubsub/howto-publish-subscribe/), [api spec](https://docs.dapr.io/reference/api/pubsub_api/) |
|
||||
| Bindings | [components-contrib/bindings](https://github.com/dapr/components-contrib/tree/master/bindings) | [Kafka](https://github.com/dapr/components-contrib/tree/master/bindings/kafka) | [concept](https://docs.dapr.io/developing-applications/building-blocks/bindings/bindings-overview/), [input howto](https://docs.dapr.io/developing-applications/building-blocks/bindings/howto-triggers/), [output howto](https://docs.dapr.io/developing-applications/building-blocks/bindings/howto-bindings/), [api spec](https://docs.dapr.io/reference/api/bindings_api/) |
|
||||
| Secret Store | [components-contrib/secretstore](https://github.com/dapr/components-contrib/tree/master/secretstores) | [Kubernetes](https://github.com/dapr/components-contrib/tree/master/secretstores/kubernetes), [Azure Keyvault](https://github.com/dapr/components-contrib/tree/master/secretstores/azure/keyvault) | [concept](https://docs.dapr.io/developing-applications/building-blocks/secrets/secrets-overview/), [howto](https://docs.dapr.io/developing-applications/building-blocks/secrets/howto-secrets/)|
|
||||
| Middleware | [components-contrib/middleware](https://github.com/dapr/components-contrib/tree/master/middleware) | [Oauth2](https://github.com/dapr/components-contrib/blob/master/middleware/http/oauth2/oauth2_middleware.go) | [concept](https://docs.dapr.io/concepts/middleware-concept/), [howto](https://docs.dapr.io/operations/security/oauth/) |
|
||||
| Exporter | [components-contrib/exporters](https://github.com/dapr/components-contrib/tree/master/exporters) | [Zipkin](https://github.com/dapr/components-contrib/blob/master/exporters/zipkin/zipkin_exporter.go) | [concept](https://docs.dapr.io/concepts/observability-concept/), [howto](https://docs.dapr.io/operations/troubleshooting/setup-tracing/) |
|
||||
| Service Discovery | [components-contrib/servicediscovery](https://github.com/dapr/components-contrib/tree/master/servicediscovery) | [mdns](https://github.com/dapr/components-contrib/blob/master/servicediscovery/mdns/mdns.go) | [howto](https://docs.dapr.io/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services/) |
|
||||
|
||||
### Running unit-test
|
||||
|
||||
|
@ -68,7 +68,7 @@ make DEBUG=1 build
|
|||
```bash
|
||||
# Back up the current daprd
|
||||
mv /usr/local/bin/daprd /usr/local/bin/daprd.bak
|
||||
cp ./dist/darwin_amd64/debug/daprd /usr/local/bin
|
||||
cp ./dist/darwin_amd64/debug/daprd ~/.dapr/bin
|
||||
```
|
||||
> Linux Debuggable Binary: ./dist/linux_amd64/debug/daprd
|
||||
> Windows Debuggable Binary: .\dist\windows_amd64\debug\daprd
|
||||
|
@ -84,7 +84,8 @@ cp ./dist/darwin_amd64/debug/daprd /usr/local/bin
|
|||
3. Fetch the latest dapr/dapr repo
|
||||
4. Update component-contrib go mod and ensure that component-contrib is updated to the latest version
|
||||
```bash
|
||||
go get -u github.com/dapr/components-contrib
|
||||
go get -u github.com/dapr/components-contrib@master
|
||||
go mod tidy
|
||||
```
|
||||
5. Import your component to Dapr [main.go](https://github.com/dapr/dapr/blob/d17e9243b308e830649b0bf3af5f6e84fd543baf/cmd/daprd/main.go#L79)
|
||||
6. Register your component in Dapr [main.go](https://github.com/dapr/dapr/blob/d17e9243b308e830649b0bf3af5f6e84fd543baf/cmd/daprd/main.go#L153-L226)
|
||||
|
|
|
@ -8,4 +8,5 @@ package exporters
|
|||
// Exporter is the interface for tracing exporter wrappers
|
||||
type Exporter interface {
|
||||
Init(daprID string, hostAddress string, metadata Metadata) error
|
||||
Unregister()
|
||||
}
|
||||
|
|
|
@ -28,7 +28,8 @@ func NewNativeExporter(logger logger.Logger) *Exporter {
|
|||
|
||||
// Exporter is an OpenCensus native exporter
|
||||
type Exporter struct {
|
||||
logger logger.Logger
|
||||
logger logger.Logger
|
||||
traceExporter trace.Exporter
|
||||
}
|
||||
|
||||
// Init creates a new native endpoint and reporter
|
||||
|
@ -43,13 +44,14 @@ func (l *Exporter) Init(daprID string, hostAddress string, metadata exporters.Me
|
|||
return nil
|
||||
}
|
||||
|
||||
exporter, err := ocagent.NewExporter(ocagent.WithInsecure(), ocagent.WithServiceName(daprID), ocagent.WithAddress(meta.AgentEndpoint))
|
||||
l.traceExporter, err = ocagent.NewExporter(ocagent.WithInsecure(), ocagent.WithServiceName(daprID), ocagent.WithAddress(meta.AgentEndpoint))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
trace.RegisterExporter(exporter)
|
||||
trace.RegisterExporter(l.traceExporter)
|
||||
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -64,5 +66,11 @@ func (l *Exporter) getNativeMetadata(metadata exporters.Metadata) (*nativeExport
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &nExporterMetadata, nil
|
||||
}
|
||||
|
||||
// Unregister removes the exporter
|
||||
func (l *Exporter) Unregister() {
|
||||
trace.UnregisterExporter(l.traceExporter)
|
||||
}
|
||||
|
|
|
@ -39,5 +39,11 @@ func (se *Exporter) Init(daprID string, hostAddress string, metadata exporters.M
|
|||
se.Buffer = metadata.Buffer
|
||||
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
|
||||
trace.RegisterExporter(se)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unregister removes the exporter
|
||||
func (se *Exporter) Unregister() {
|
||||
trace.UnregisterExporter(se)
|
||||
}
|
||||
|
|
|
@ -30,7 +30,8 @@ func NewZipkinExporter(logger logger.Logger) *Exporter {
|
|||
|
||||
// Exporter is an OpenCensus zipkin exporter
|
||||
type Exporter struct {
|
||||
logger logger.Logger
|
||||
logger logger.Logger
|
||||
traceExporter trace.Exporter
|
||||
}
|
||||
|
||||
// Init creates a new zipkin endpoint and reporter
|
||||
|
@ -50,9 +51,10 @@ func (z *Exporter) Init(daprID string, hostAddress string, metadata exporters.Me
|
|||
return err
|
||||
}
|
||||
reporter := zipkinHTTP.NewReporter(meta.ExporterAddress)
|
||||
ze := zipkin.NewExporter(reporter, localEndpoint)
|
||||
trace.RegisterExporter(ze)
|
||||
z.traceExporter = zipkin.NewExporter(reporter, localEndpoint)
|
||||
trace.RegisterExporter(z.traceExporter)
|
||||
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -67,5 +69,11 @@ func (z *Exporter) getZipkinMetadata(metadata exporters.Metadata) (*zipkinMetada
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &zipkinMeta, nil
|
||||
}
|
||||
|
||||
// Unregister removes the exporter
|
||||
func (z *Exporter) Unregister() {
|
||||
trace.UnregisterExporter(z.traceExporter)
|
||||
}
|
||||
|
|
36
go.mod
36
go.mod
|
@ -3,10 +3,10 @@ module github.com/dapr/components-contrib
|
|||
go 1.14
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.52.0
|
||||
cloud.google.com/go/datastore v1.0.0
|
||||
cloud.google.com/go/pubsub v1.0.1
|
||||
cloud.google.com/go/storage v1.0.0
|
||||
cloud.google.com/go v0.65.0
|
||||
cloud.google.com/go/datastore v1.1.0
|
||||
cloud.google.com/go/pubsub v1.3.1
|
||||
cloud.google.com/go/storage v1.10.0
|
||||
contrib.go.opencensus.io/exporter/ocagent v0.6.0
|
||||
contrib.go.opencensus.io/exporter/zipkin v0.1.1
|
||||
github.com/Azure/azure-event-hubs-go v1.3.1
|
||||
|
@ -19,14 +19,16 @@ require (
|
|||
github.com/Azure/go-autorest/autorest/adal v0.8.3
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.4.2
|
||||
github.com/Shopify/sarama v1.23.1
|
||||
github.com/a8m/documentdb v1.2.0
|
||||
github.com/a8m/documentdb v1.2.1-0.20190920062420-efdd52fe0905
|
||||
github.com/aerospike/aerospike-client-go v2.7.0+incompatible
|
||||
github.com/alicebob/miniredis/v2 v2.13.3
|
||||
github.com/aliyun/aliyun-oss-go-sdk v2.0.7+incompatible
|
||||
github.com/apache/pulsar-client-go v0.1.0
|
||||
github.com/aws/aws-sdk-go v1.25.0
|
||||
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b
|
||||
github.com/coreos/go-oidc v2.1.0+incompatible
|
||||
github.com/dancannon/gorethink v4.0.0+incompatible
|
||||
github.com/dapr/dapr v0.4.1-0.20200228055659-71892bc0111e
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73
|
||||
github.com/dghubble/go-twitter v0.0.0-20190719072343-39e5462e111f
|
||||
|
@ -37,8 +39,8 @@ require (
|
|||
github.com/fasthttp-contrib/sessions v0.0.0-20160905201309-74f6ac73d5d5
|
||||
github.com/go-redis/redis/v7 v7.0.1
|
||||
github.com/gocql/gocql v0.0.0-20191018090344-07ace3bab0f8
|
||||
github.com/golang/mock v1.4.0
|
||||
github.com/golang/protobuf v1.3.3
|
||||
github.com/golang/mock v1.4.4
|
||||
github.com/golang/protobuf v1.4.2
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/grandcat/zeroconf v0.0.0-20190424104450-85eadb44205c
|
||||
github.com/hashicorp/consul/api v1.2.0
|
||||
|
@ -47,12 +49,13 @@ require (
|
|||
github.com/influxdata/influxdb-client-go v1.4.0
|
||||
github.com/jackc/pgx/v4 v4.6.0
|
||||
github.com/json-iterator/go v1.1.8
|
||||
github.com/lib/pq v1.8.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.3.2 // indirect
|
||||
github.com/nats-io/gnatsd v1.4.1
|
||||
github.com/nats-io/go-nats v1.7.2
|
||||
github.com/nats-io/nats-streaming-server v0.17.0 // indirect
|
||||
github.com/nats-io/nats.go v1.9.1
|
||||
github.com/nats-io/stan.go v0.6.0
|
||||
github.com/open-policy-agent/opa v0.23.2
|
||||
github.com/openzipkin/zipkin-go v0.1.6
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/pkg/errors v0.9.1
|
||||
|
@ -65,21 +68,20 @@ require (
|
|||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271
|
||||
github.com/stretchr/testify v1.5.1
|
||||
github.com/tidwall/pretty v1.0.1 // indirect
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc // indirect
|
||||
github.com/valyala/fasthttp v1.6.0
|
||||
github.com/vmware/vmware-go-kcl v0.0.0-20191104173950-b6c74c3fe74e
|
||||
go.etcd.io/etcd v3.3.17+incompatible
|
||||
go.mongodb.org/mongo-driver v1.1.2
|
||||
go.opencensus.io v0.22.3
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||
google.golang.org/api v0.15.0
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150
|
||||
google.golang.org/grpc v1.26.0
|
||||
go.opencensus.io v0.22.4
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43
|
||||
google.golang.org/api v0.32.0
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d
|
||||
google.golang.org/grpc v1.32.0
|
||||
gopkg.in/couchbase/gocb.v1 v1.6.4
|
||||
gopkg.in/couchbase/gocbcore.v7 v7.1.16 // indirect
|
||||
gopkg.in/couchbaselabs/gojcbmock.v1 v1.0.4 // indirect
|
||||
gopkg.in/gorethink/gorethink.v4 v4.1.0 // indirect
|
||||
k8s.io/api v0.17.0
|
||||
k8s.io/apimachinery v0.17.0
|
||||
k8s.io/client-go v0.17.0
|
||||
|
|
339
go.sum
339
go.sum
|
@ -6,16 +6,40 @@ cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK
|
|||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3 h1:AVXDdKsrtX33oR9fbCMu/+c1o8Ofjq6Ku/MInaLVg5Y=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0 h1:GGslhk/BU052LPlnI1vpp3fcbUs+hQ3E+Doti/3/vF8=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go/bigquery v1.0.1 h1:hL+ycaJpVE9M7nLoiXb/Pn10ENE2u+oddxbD8uu0ZVU=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0 h1:Kt+gOPPp2LEPWp8CSfxhsM8ik9CcyE/gYu+0r+RnZvM=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1 h1:W9tAK3E57P75u0XLLR82LZyw8VpAnhmyTOxW9qzmyj8=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1 h1:ukjixP1wl0LpnZ6LWtZJ0mX5tBmjp1f8Sqer8Z2OMUU=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0 h1:VV2nUM3wwLLGh9lSABFgZMjInyUbJeaRSE64WuAIQ+4=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0 h1:STgFzyU5/8miMl0//zKh2aQeTyeaUH3WN9bSUiJ09bA=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0=
|
||||
contrib.go.opencensus.io/exporter/ocagent v0.6.0 h1:Z1n6UAyr0QwM284yUuh5Zd8JlvxUGAhFZcgMJkMPrGM=
|
||||
contrib.go.opencensus.io/exporter/ocagent v0.6.0/go.mod h1:zmKjrJcdo0aYcVS7bmEeSEBLPA9YJp5bjrofdU3pIXs=
|
||||
|
@ -108,6 +132,8 @@ github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798 h1:2T/jmrHeTezcCM58
|
|||
github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/OneOfOne/xxhash v1.2.7 h1:fzrmmkskv067ZQbd9wERNGuxckWw67dyzoMG62p7LMo=
|
||||
github.com/OneOfOne/xxhash v1.2.7/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
|
||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
|
@ -119,6 +145,8 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWso
|
|||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/a8m/documentdb v1.2.0 h1:3ooHoXI6ww5d5Itr39V+bBmX4xm0nKrv0XMKbXw8vwE=
|
||||
github.com/a8m/documentdb v1.2.0/go.mod h1:4Z0mpi7fkyqjxUdGiNMO3vagyiUoiwLncaIX6AsW5z0=
|
||||
github.com/a8m/documentdb v1.2.1-0.20190920062420-efdd52fe0905 h1:lrOYmNobGcyWEjvMIMJERJx1Y4ttPFobY7RHAD+6e10=
|
||||
github.com/a8m/documentdb v1.2.1-0.20190920062420-efdd52fe0905/go.mod h1:4Z0mpi7fkyqjxUdGiNMO3vagyiUoiwLncaIX6AsW5z0=
|
||||
github.com/aerospike/aerospike-client-go v2.7.0+incompatible h1:NbjGs0ZMHKge1+0m+XLdhcDm/2gCfjnlasSTtKSr8j4=
|
||||
github.com/aerospike/aerospike-client-go v2.7.0+incompatible/go.mod h1:zj8LBEnWBDOVEIJt8LvaRvDG5ARAoa5dBeHaB472NRc=
|
||||
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||
|
@ -127,6 +155,10 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
|
|||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
|
||||
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
|
||||
github.com/alicebob/miniredis/v2 v2.13.3 h1:kohgdtN58KW/r9ZDVmMJE3MrfbumwsDQStd0LPAGmmw=
|
||||
github.com/alicebob/miniredis/v2 v2.13.3/go.mod h1:uS970Sw5Gs9/iK3yBg0l9Uj9s25wXxSpQUE9EaJ/Blg=
|
||||
github.com/aliyun/aliyun-oss-go-sdk v2.0.7+incompatible h1:HXvOJsZw8JT/ldxjX74Aq4H2IY4ojV/mXMDPWFitpv8=
|
||||
github.com/aliyun/aliyun-oss-go-sdk v2.0.7+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
||||
github.com/apache/pulsar-client-go v0.1.0 h1:2BFZztxtNgFyOzBc+5On84CX6aIZW5xwh7KM0MWigGI=
|
||||
|
@ -159,6 +191,7 @@ github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D
|
|||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||
github.com/cenkalti/backoff v2.0.0+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
|
@ -175,6 +208,7 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
|
|||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY=
|
||||
|
@ -196,6 +230,8 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc
|
|||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
||||
github.com/dancannon/gorethink v4.0.0+incompatible h1:KFV7Gha3AuqT+gr0B/eKvGhbjmUv0qGF43aKCIKVE9A=
|
||||
github.com/dancannon/gorethink v4.0.0+incompatible/go.mod h1:BLvkat9KmZc1efyYwhz3WnybhRZtgF1K929FD8z1avU=
|
||||
github.com/dapr/components-contrib v0.0.0-20200219164914-5b75f4d0fbc6/go.mod h1:AZi8IGs8LFdywJg/YGwDs7MAxJkvGa8RgHN4NoJSKt0=
|
||||
github.com/dapr/dapr v0.4.1-0.20200228055659-71892bc0111e h1:njRp/SZ/zgqjSDywmy+Dn9oikkZqkqAHWGbfMarUuwo=
|
||||
github.com/dapr/dapr v0.4.1-0.20200228055659-71892bc0111e/go.mod h1:c60DJ9TdSdpbLjgqP55A5u4ZCYChFwa9UGYIXd9pmm4=
|
||||
|
@ -222,7 +258,6 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
|
|||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/didip/tollbooth v4.0.2+incompatible h1:fVSa33JzSz0hoh2NxpwZtksAzAgd7zjmGO20HCZtF4M=
|
||||
github.com/didip/tollbooth v4.0.2+incompatible/go.mod h1:A9b0665CE6l1KmzpDws2++elm/CsuWBMa5Jv4WY0PEY=
|
||||
github.com/dimchansky/utfbom v1.0.0 h1:fGC2kkf4qOoKqZ4q7iIh+Vef4ubC1c38UDsEyZynZPc=
|
||||
github.com/dimchansky/utfbom v1.0.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
||||
github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4=
|
||||
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
||||
|
@ -230,7 +265,6 @@ github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY=
|
|||
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/eapache/go-resiliency v1.1.0 h1:1NtRmCAqadE2FN4ZcN6g90TP3uk8cg9rn9eNK2197aU=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q=
|
||||
github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
|
@ -244,10 +278,11 @@ github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkg
|
|||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/go-restful v2.10.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I=
|
||||
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fasthttp-contrib/sessions v0.0.0-20160905201309-74f6ac73d5d5 h1:M4CVMQ5ueVmGZAtkW2bsO+ftesCYpfxl27JTqtzKBzE=
|
||||
github.com/fasthttp-contrib/sessions v0.0.0-20160905201309-74f6ac73d5d5/go.mod h1:MQXNGeXkpojWTxbN7vXoE3f7EmlA11MlJbsrJpVBINA=
|
||||
|
@ -256,24 +291,25 @@ github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod
|
|||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/fortytw2/leaktest v1.2.0 h1:cj6GCiwJDH7l3tMHLjZDo0QqPtrXJiWSI9JgpeQKw+Q=
|
||||
github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
||||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||
github.com/frankban/quicktest v1.5.0/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc=
|
||||
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||
github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8=
|
||||
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
|
||||
github.com/getkin/kin-openapi v0.2.0/go.mod h1:V1z9xl9oF5Wt7v32ne4FmiF1alpS4dM6mNzoywPOXlk=
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
github.com/go-chi/chi v4.0.3+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
|
@ -294,25 +330,22 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
|
|||
github.com/go-ozzo/ozzo-routing v2.1.4+incompatible/go.mod h1:hvoxy5M9SJaY0viZvcCsODidtUm5CzRbYKEWuQpr+2A=
|
||||
github.com/go-redis/redis/v7 v7.0.1 h1:AVkqXtvak6eXAvqIA+0rDlh6St/M7/vaf67NEqPhP2w=
|
||||
github.com/go-redis/redis/v7 v7.0.1/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
|
||||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/gocql/gocql v0.0.0-20191018090344-07ace3bab0f8 h1:ZyxBBeTImqFLu9mLtQUnXrO8K/SryXE/xjG/ygl0DxQ=
|
||||
github.com/gocql/gocql v0.0.0-20191018090344-07ace3bab0f8/go.mod h1:DL0ekTmBSTdlNF25Orwt/JMzqIq3EJ4MVa/J/uK64OY=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415 h1:WSBJMqJbLxsn+bTCPyPYZfqHdJmc8MK4wrBjMft6BAM=
|
||||
github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.0 h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE=
|
||||
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
|
@ -322,23 +355,37 @@ github.com/golang/gddo v0.0.0-20190815223733-287de01127ef/go.mod h1:xEhNfoBDX1hz
|
|||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0 h1:Rd1kQnQu0Hq3qvJppYSG0HtP+f5LPPUiDswTLiEegLg=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v0.0.0-20181025225059-d3de96c4c28e/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
|
@ -349,11 +396,16 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z
|
|||
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
|
@ -362,9 +414,15 @@ github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
|||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0 h1:pMen7vLs8nvgEYhywH3KDWJIJTeEr2ULsVWHWYHQyBs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
|
@ -372,7 +430,6 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
|||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=
|
||||
github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
|
||||
|
@ -380,9 +437,8 @@ github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8/go.mod h1:
|
|||
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
|
||||
github.com/gorilla/mux v0.0.0-20181024020800-521ea7b17d02/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
|
@ -416,7 +472,6 @@ github.com/hashicorp/go-hclog v0.9.1 h1:9PZfAcVEvez4yhLH2TBU64/h/z4xlFI80cWXRrxu
|
|||
github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI=
|
||||
github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
|
@ -500,8 +555,8 @@ github.com/jackc/pgx/v4 v4.6.0 h1:Fh0O9GdlG4gYpjpwOqjdEodJUQM9jzN3Hdv7PN0xmm0=
|
|||
github.com/jackc/pgx/v4 v4.6.0/go.mod h1:vPh43ZzxijXUVJ+t/EmXBtFmbFVO72cuneCT9oAlxAg=
|
||||
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.0 h1:musOWczZC/rSbqut475Vfcczg7jJsdUQf0D6oKPLgNU=
|
||||
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03 h1:FUwcHNlEqkqLjLBdCp5PRlCFijNjvcYANOZXzCfXwCM=
|
||||
github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
|
||||
github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8=
|
||||
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
|
||||
|
@ -511,9 +566,7 @@ github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
|||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/joomcode/errorx v1.0.0 h1:RJAKLTy1Sv2Tszhu14m5RZP4VGRlhXutG/XlL1En5VM=
|
||||
github.com/joomcode/errorx v1.0.0/go.mod h1:kgco15ekB6cs+4Xjzo7SPeXzx38PbJzBwbnu9qfVNHQ=
|
||||
github.com/joomcode/redispipe v0.9.0 h1:NukwwIvxhg6r2lVxa1RJhEZXYPZZF/OX9WZJk+2cK1Q=
|
||||
github.com/joomcode/redispipe v0.9.0/go.mod h1:4S/gpBCZ62pB/3+XLNWDH7jQnB0vxmpddAMBva2adpM=
|
||||
github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7 h1:K//n/AqR5HjG3qxbrBCL4vJPW0MVFSs9CPK1OOJdRME=
|
||||
github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
|
||||
|
@ -521,11 +574,9 @@ github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBv
|
|||
github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024 h1:rBMNdlhTLzJjJSDIjNEXX1Pz3Hmwmz91v+zycvx9PJc=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
|
@ -542,14 +593,11 @@ github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa
|
|||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.8.2 h1:Bx0qjetmNjdFXASH02NSAREKpiaDwkO1DRZ3dV2KCcs=
|
||||
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.9.2 h1:LfVyl+ZlLlLDeQ/d2AqfGIIH4qEDu0Ed2S5GyhCWIWY=
|
||||
github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
|
||||
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
|
@ -561,9 +609,7 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
|||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kubernetes-client/go v0.0.0-20190625181339-cd8e39e789c7 h1:NZlvd1Qf3MwoRhh87iVkJSHK3R31fX3D7kQfdJy6LnQ=
|
||||
github.com/kubernetes-client/go v0.0.0-20190625181339-cd8e39e789c7/go.mod h1:ks4KCmmxdXksTSu2dlnUanEOqNd/dsoyS6/7bay2RQ8=
|
||||
github.com/kubernetes-client/go v0.0.0-20190928040339-c757968c4c36 h1:/VKCfQgtQxBXEVU9UAJkW/ybm/070TBG57x2wxYUtXI=
|
||||
github.com/kubernetes-client/go v0.0.0-20190928040339-c757968c4c36/go.mod h1:ks4KCmmxdXksTSu2dlnUanEOqNd/dsoyS6/7bay2RQ8=
|
||||
github.com/labstack/echo/v4 v4.1.11 h1:z0BZoArY4FqdpUEl+wlHp4hnr/oSR6MTmQmv8OHSoww=
|
||||
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
|
||||
|
@ -571,10 +617,10 @@ github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0
|
|||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
|
||||
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
|
||||
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
|
@ -582,27 +628,23 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN
|
|||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
||||
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149 h1:HfxbT6/JcvIljmERptWhwa8XzP7H3T+Z2N26gTsaDaA=
|
||||
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
||||
github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-runewidth v0.0.0-20181025052659-b20a3daf6a39/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mediocregopher/radix.v2 v0.0.0-20181115013041-b67df6e626f9 h1:ViNuGS149jgnttqhc6XQNPwdupEMBXqCx9wtlW7P3sA=
|
||||
github.com/mediocregopher/radix.v2 v0.0.0-20181115013041-b67df6e626f9/go.mod h1:fLRUbhbSd5Px2yKUaGYYPltlyxi1guJz1vCmo1RQL50=
|
||||
github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s=
|
||||
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
|
||||
|
@ -610,7 +652,6 @@ github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA=
|
|||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
|
@ -619,7 +660,6 @@ github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eI
|
|||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg=
|
||||
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
|
@ -640,16 +680,13 @@ github.com/nats-io/gnatsd v1.4.1/go.mod h1:nqco77VO78hLCJpIcVfygDP2rPGfsEHkGTUk9
|
|||
github.com/nats-io/go-nats v1.7.2 h1:cJujlwCYR8iMz5ofZSD/p2WLW8FabhkQ2lIEVbSvNSA=
|
||||
github.com/nats-io/go-nats v1.7.2/go.mod h1:+t7RHT5ApZebkrQdnn6AhQJmhJJiKAvJUio1PiiCtj0=
|
||||
github.com/nats-io/jwt v0.2.14/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
|
||||
github.com/nats-io/jwt v0.3.0 h1:xdnzwFETV++jNc4W1mw//qFyJGb2ABOombmZJQS4+Qo=
|
||||
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
|
||||
github.com/nats-io/jwt v0.3.2 h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI=
|
||||
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
|
||||
github.com/nats-io/nats-server/v2 v2.0.4/go.mod h1:AWdGEVbjKRS9ZIx4DSP5eKW48nfFm7q3uiSkP/1KD7M=
|
||||
github.com/nats-io/nats-server/v2 v2.1.2 h1:i2Ly0B+1+rzNZHHWtD4ZwKi+OU5l+uQo1iDHZ2PmiIc=
|
||||
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
|
||||
github.com/nats-io/nats-server/v2 v2.1.4 h1:BILRnsJ2Yb/fefiFbBWADpViGF69uh4sxe8poVDQ06g=
|
||||
github.com/nats-io/nats-server/v2 v2.1.4/go.mod h1:Jw1Z28soD/QasIA2uWjXyM9El1jly3YwyFOuR8tH1rg=
|
||||
github.com/nats-io/nats-streaming-server v0.16.2 h1:RyTg8dZ+A8LaDEEmh9BoHFxWJSuSrIGJ4xjsr0fLMeY=
|
||||
github.com/nats-io/nats-streaming-server v0.16.2/go.mod h1:P12vTqmBpT6Ufs+cu0W1C4N2wmISqa6G4xdLQeO2e2s=
|
||||
github.com/nats-io/nats-streaming-server v0.17.0 h1:eYhSmjRmRsCYNsoUshmZ+RgKbhq6B+7FvMHXo3M5yMs=
|
||||
github.com/nats-io/nats-streaming-server v0.17.0/go.mod h1:ewPBEsmp62Znl3dcRsYtlcfwudxHEdYMtYqUQSt4fE0=
|
||||
|
@ -657,7 +694,6 @@ github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ
|
|||
github.com/nats-io/nats.go v1.9.1 h1:ik3HbLhZ0YABLto7iX80pZLPw/6dx3T+++MZJwLnMrQ=
|
||||
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
|
||||
github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4=
|
||||
github.com/nats-io/nkeys v0.1.0 h1:qMd4+pRHgdr1nAClu+2h/2a5F2TmKcCzjCDazVgRoX4=
|
||||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nkeys v0.1.3 h1:6JrEfig+HzTH85yxzhSVbjHRJv9cn0p6n3IngIcM5/k=
|
||||
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
|
@ -667,28 +703,26 @@ github.com/nats-io/stan.go v0.5.0/go.mod h1:dYqB+vMN3C2F9pT1FRQpg9eHbjPj6mP0yYuy
|
|||
github.com/nats-io/stan.go v0.6.0 h1:26IJPeykh88d8KVLT4jJCIxCyUBOC5/IQup8oWD/QYY=
|
||||
github.com/nats-io/stan.go v0.6.0/go.mod h1:eIcD5bi3pqbHT/xIIvXMwvzXYElgouBvaVRftaE+eac=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.2 h1:uqH7bpe+ERSiDa34FDOF7RikN6RzXgduUF8yarlZp94=
|
||||
github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3 h1:EooPXg51Tn+xmWPXJUGCnJhJSpeuMlBmfJVcqIRmmv8=
|
||||
github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/open-policy-agent/opa v0.23.2 h1:co9fPjnLPwnvaEThBJjCb5E2iAyvW95Qq2PvSOEIwGE=
|
||||
github.com/open-policy-agent/opa v0.23.2/go.mod h1:rrwxoT/b011T0cyj+gg2VvxqTtn6N3gp/jzmr3fjW44=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/openzipkin/zipkin-go v0.1.1 h1:A/ADD6HaPnAKj3yS7HjGHRK77qi41Hi0DirOOIQAeIw=
|
||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
github.com/openzipkin/zipkin-go v0.1.6 h1:yXiysv1CSK7Q5yjGy1710zZGnsbMUIjluWBxtLXHPBo=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
|
@ -696,12 +730,13 @@ github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaR
|
|||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/peterh/liner v0.0.0-20170211195444-bf27d3ba8e1d/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
|
||||
github.com/phayes/freeport v0.0.0-20171002181615-b8543db493a5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
||||
github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.0.0-20181023235946-059132a15dd0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
|
@ -712,6 +747,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
|||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
|
||||
github.com/prometheus/client_golang v0.0.0-20181025174421-f30f42803563/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
||||
|
@ -721,16 +757,15 @@ github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvls
|
|||
github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY=
|
||||
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
||||
github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
|
||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||
|
@ -741,7 +776,6 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z
|
|||
github.com/prometheus/procfs v0.0.0-20190523193104-a7aeb8df3389/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
|
||||
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
|
@ -771,7 +805,6 @@ github.com/sendgrid/rest v2.4.1+incompatible h1:HDib/5xzQREPq34lN3YMhQtMkdXxS/qL
|
|||
github.com/sendgrid/rest v2.4.1+incompatible/go.mod h1:kXX7q3jZtJXK5c5qK83bSGMdV6tsOE70KbHoqJls4lE=
|
||||
github.com/sendgrid/sendgrid-go v3.5.0+incompatible h1:kosbgHyNVYVaqECDYvFVLVD9nvThweBd6xp7vaCT3GI=
|
||||
github.com/sendgrid/sendgrid-go v3.5.0+incompatible/go.mod h1:QRQt+LX/NmgVEvmdRw0VT/QgUn499+iza2FnDca9fg8=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
|
@ -779,7 +812,7 @@ github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t4
|
|||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.1.1 h1:VzGj7lhU7KEB9e9gMpAV/v5XT2NVSvLJhJLCWbnkgXg=
|
||||
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||
github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
|
@ -797,12 +830,12 @@ github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2
|
|||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.0-20181021141114-fe5e611709b0/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4=
|
||||
github.com/spf13/pflag v0.0.0-20181024212040-082b515c9490/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
|
@ -811,25 +844,19 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM
|
|||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271 h1:WhxRHzgeVGETMlmVfqhRn8RIeeNoPr2Czh33I4Zdccw=
|
||||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tidwall/pretty v1.0.1 h1:WE4RBSZ1x6McVVC8S/Md+Qse8YUv6HRObAx6ke00NY8=
|
||||
github.com/tidwall/pretty v1.0.1/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc h1:yUaosFVTJwnltaHbSNC3i82I92quFs+OFPRl8kNMVwo=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
|
@ -857,12 +884,18 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
|
|||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
|
||||
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
|
||||
github.com/yashtewari/glob-intersection v0.0.0-20180916065949-5c77d914dd0b h1:vVRagRXf67ESqAb72hG2C/ZwI8NtJF2u2V76EsuOHGY=
|
||||
github.com/yashtewari/glob-intersection v0.0.0-20180916065949-5c77d914dd0b/go.mod h1:HptNXiXVDcJjXe9SqMd0v2FsL9f8dz4GnXgltU6q/co=
|
||||
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
|
||||
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
|
||||
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
|
||||
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
|
||||
github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI=
|
||||
github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0=
|
||||
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
|
@ -876,10 +909,11 @@ go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0=
|
|||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
|
@ -887,10 +921,10 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
|
|||
go.uber.org/multierr v1.2.0 h1:6I+W7f5VwC5SV9dNrZ3qXrDB9mD0dyGOi/ZJmYw03T4=
|
||||
go.uber.org/multierr v1.2.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.11.0 h1:gSmpCfs+R47a4yQPAI4xJ0IPDLTRGXskm6UelqNXpqE=
|
||||
go.uber.org/zap v1.11.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
|
@ -907,41 +941,50 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
|||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g=
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200206161412-a0c6ece9d31a h1:aczoJ0HPNE92XKa7DrIzkNN6esOKO2TBwiiYoKcINhA=
|
||||
golang.org/x/crypto v0.0.0-20200206161412-a0c6ece9d31a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM=
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979 h1:Agxu5KLo8o7Bb634SVDnhIfpTvxmzUwhbYAzBvXt6h4=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299 h1:zQpM52jfKHG6II1ISZY1ZcpygvuSFZpLwfluuF89XOg=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181023182221-1baf3a9d7d67/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac h1:8R1esu+8QioDxo4E4mX6bFztO+dMTM49DNAaWfO5OeY=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -963,35 +1006,51 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||
golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM=
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 h1:ld7aEMNHoBnnDAX15v1T6z31v8HwR2A9FYOuAhWqkwc=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180828065106-d99a578cf41b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -1020,17 +1079,28 @@ golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1 h1:gZpLHxUX5BdYLA08Lj4YCJNN/jk7KtquiArPoeX0WvA=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f h1:Fqb3ao1hUmOR3GkUOg/Y+BadLwykBIzs5q8Ez2SbHyc=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -1038,10 +1108,14 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
|
|||
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
@ -1065,17 +1139,44 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw
|
|||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c h1:2EA2K0k9bcvvEDlqD8xdlOhCOqq+O/p9Voqi4x9W1YU=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858 h1:xLt+iB5ksWcZVxqc+g9K41ZHy+6MKWfXCDsjSThnsPA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0=
|
||||
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
||||
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ=
|
||||
|
@ -1085,15 +1186,29 @@ google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1
|
|||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0 h1:yzlyyDW/J0w8yNFJIhiAJy4kq74S+1DOLdawELNxFMA=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.32.0 h1:Le77IccnTqEa8ryp9wIpX5W3zYm7Gf9LhOp9PHcwFts=
|
||||
google.golang.org/api v0.32.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
|
@ -1104,11 +1219,31 @@ google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dT
|
|||
google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51 h1:Ex1mq5jaJof+kRnYi3SlYJ8KKa9Ao3NHyIT5XJ1gF6U=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150 h1:VPpdpQkGvFicX9yo4G5oxZPi9ALBnEOZblPSa/Wa2m4=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d h1:92D1fum1bJLKSdr11OJ+54YeCMCGYIygTA7R/YZxH5M=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
|
@ -1117,34 +1252,55 @@ google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij
|
|||
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0=
|
||||
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/couchbase/gocb.v1 v1.6.4 h1:vAworfH5ZKDbonmayrwbGiD9jkAMroWmHXDf1GAIqMM=
|
||||
gopkg.in/couchbase/gocb.v1 v1.6.4/go.mod h1:Ri5Qok4ZKiwmPr75YxZ0uELQy45XJgUSzeUnK806gTY=
|
||||
gopkg.in/couchbase/gocbcore.v7 v7.1.15 h1:2nhfrqKz6TBex0Vcc+iq9UnAZltfCGklnM4mgdf2I3o=
|
||||
gopkg.in/couchbase/gocbcore.v7 v7.1.15/go.mod h1:48d2Be0MxRtsyuvn+mWzqmoGUG9uA00ghopzOs148/E=
|
||||
gopkg.in/couchbase/gocbcore.v7 v7.1.16 h1:n2foZ0Lg2ooBhgzgIpIxQ7VmlUbL6x0GwrP0GQcmTYo=
|
||||
gopkg.in/couchbase/gocbcore.v7 v7.1.16/go.mod h1:48d2Be0MxRtsyuvn+mWzqmoGUG9uA00ghopzOs148/E=
|
||||
gopkg.in/couchbaselabs/gocbconnstr.v1 v1.0.4 h1:VVVoIV/nSw1w9ZnTEOjmkeJVcAzaCyxEujKglarxz7U=
|
||||
gopkg.in/couchbaselabs/gocbconnstr.v1 v1.0.4/go.mod h1:ZjII0iKx4Veo6N6da+pEZu/ptNyKLg9QTVt7fFmR6sw=
|
||||
gopkg.in/couchbaselabs/gojcbmock.v1 v1.0.3 h1:7n5tht07rEuogME6fmi6FVglIAUFD8m4t8ZQbnUq0sA=
|
||||
gopkg.in/couchbaselabs/gojcbmock.v1 v1.0.3/go.mod h1:jl/gd/aQ2S8whKVSTnsPs6n7BPeaAuw9UglBD/OF7eo=
|
||||
gopkg.in/couchbaselabs/gojcbmock.v1 v1.0.4 h1:r5WoWGyeTJQiNGsoWAsMJfz0JFF14xc2TJrYSs09VXk=
|
||||
gopkg.in/couchbaselabs/gojcbmock.v1 v1.0.4/go.mod h1:jl/gd/aQ2S8whKVSTnsPs6n7BPeaAuw9UglBD/OF7eo=
|
||||
gopkg.in/couchbaselabs/jsonx.v1 v1.0.0 h1:SJGarb8dXAsVZWizC26rxBkBYEKhSUxVh5wAnyzBVaI=
|
||||
gopkg.in/couchbaselabs/jsonx.v1 v1.0.0/go.mod h1:oR201IRovxvLW/eISevH12/+MiKHtNQAKfcX8iWZvJY=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fatih/pool.v2 v2.0.0 h1:xIFeWtxifuQJGk/IEPKsTduEKcKvPmhoiVDGpC40nKg=
|
||||
gopkg.in/fatih/pool.v2 v2.0.0/go.mod h1:8xVGeu1/2jr2wm5V9SPuMht2H5AEmf5aFMGSQixtjTY=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gorethink/gorethink.v4 v4.1.0 h1:xoE9qJ9Ae9KdKEsiQGCF44u2JdnjyohrMBRDtts3Gjw=
|
||||
gopkg.in/gorethink/gorethink.v4 v4.1.0/go.mod h1:M7JgwrUAmshJ3iUbEK0Pt049MPyPK+CYDGGaEjdZb/c=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/inf.v0 v0.9.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o=
|
||||
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
|
@ -1154,7 +1310,6 @@ gopkg.in/jcmturner/dnsutils.v1 v1.0.1 h1:cIuC1OLRGZrld+16ZJvvZxVJeKPsvd5eUIvxfoN
|
|||
gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q=
|
||||
gopkg.in/jcmturner/goidentity.v3 v3.0.0 h1:1duIyWiTaYvVx3YX2CYtpJbUFd7/UuPYCfgXtQ3VTbI=
|
||||
gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4=
|
||||
gopkg.in/jcmturner/gokrb5.v7 v7.2.3 h1:hHMV/yKPwMnJhPuPx7pH2Uw/3Qyf+thJYlisUc44010=
|
||||
gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM=
|
||||
gopkg.in/jcmturner/gokrb5.v7 v7.3.0 h1:0709Jtq/6QXEuWRfAm260XqlpcwL1vxtO1tUE2qK8Z4=
|
||||
gopkg.in/jcmturner/gokrb5.v7 v7.3.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM=
|
||||
|
@ -1171,7 +1326,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep
|
|||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
@ -1184,18 +1338,16 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh
|
|||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
k8s.io/api v0.0.0-20190620084959-7cf5895f2711 h1:BblVYz/wE5WtBsD/Gvu54KyBUTJMflolzc5I2DTvh50=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.0.0-20190620084959-7cf5895f2711/go.mod h1:TBhBqb1AWbBQbW3XRusr7n7E4v2+5ZY8r8sAMnyFC5A=
|
||||
k8s.io/api v0.17.0 h1:H9d/lw+VkZKEVIUc8F3wgiQ+FUXTTr21M87jXLU7yqM=
|
||||
k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI=
|
||||
k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719 h1:uV4S5IB5g4Nvi+TBVNf3e9L4wrirlwYJ6w88jUQxTUw=
|
||||
k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719/go.mod h1:I4A+glKBHiTgiEjQiCCQfCAIcIMFGt291SmsvcrFzJA=
|
||||
k8s.io/apimachinery v0.0.0-20190817020851-f2f3a405f61d h1:7Kns6qqhMAQWvGkxYOLSLRZ5hJO0/5pcE5lPGP2fxUw=
|
||||
k8s.io/apimachinery v0.0.0-20190817020851-f2f3a405f61d/go.mod h1:3jediapYqJ2w1BFw7lAZPCx7scubsTfosqHkhXCWJKw=
|
||||
k8s.io/apimachinery v0.17.0 h1:xRBnuie9rXcPxUkDizUsGvPf1cnlZCFu210op7J7LJo=
|
||||
k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
|
||||
k8s.io/cli-runtime v0.17.0/go.mod h1:1E5iQpMODZq2lMWLUJELwRu2MLWIzwvMgDBpn3Y81Qo=
|
||||
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab h1:E8Fecph0qbNsAbijJJQryKu4Oi9QTp5cVpjTE+nqg6g=
|
||||
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab/go.mod h1:E95RaSlHr79aHaX0aGSwcPNfygDiPKOVXdmivCIZT0k=
|
||||
k8s.io/client-go v0.17.0 h1:8QOGvUGdqDMFrm9sD6IUFl256BcffynGoe80sxgTEDg=
|
||||
k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k=
|
||||
|
@ -1204,16 +1356,13 @@ k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8
|
|||
k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v0.3.1 h1:RVgyDHY/kFKtLqh67NvEWIgkMneNoIrdkN0CxDSQc68=
|
||||
k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
||||
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||
k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
|
||||
k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
|
||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU=
|
||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
|
||||
k8s.io/utils v0.0.0-20190221042446-c2654d5206da h1:ElyM7RPonbKnQqOcw7dG2IK5uvQQn3b/WPHqD5mBvP4=
|
||||
k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
|
||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo=
|
||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
|
|
|
@ -6,9 +6,8 @@
|
|||
package bearer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
oidc "github.com/coreos/go-oidc"
|
||||
|
@ -40,7 +39,6 @@ const (
|
|||
// GetHandler retruns the HTTP handler provided by the middleware
|
||||
func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.RequestHandler) fasthttp.RequestHandler, error) {
|
||||
meta, err := m.getNativeMetadata(metadata)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -59,12 +57,14 @@ func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.R
|
|||
authHeader := string(ctx.Request.Header.Peek(fasthttp.HeaderAuthorization))
|
||||
if !strings.HasPrefix(strings.ToLower(authHeader), bearerPrefix) {
|
||||
ctx.Error(fasthttp.StatusMessage(fasthttp.StatusUnauthorized), fasthttp.StatusUnauthorized)
|
||||
|
||||
return
|
||||
}
|
||||
rawToken := authHeader[bearerPrefixLength:]
|
||||
_, err := verifier.Verify(ctx, rawToken)
|
||||
if err != nil {
|
||||
ctx.Error(fasthttp.StatusMessage(fasthttp.StatusUnauthorized), fasthttp.StatusUnauthorized)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -84,5 +84,6 @@ func (m *Middleware) getNativeMetadata(metadata middleware.Metadata) (*bearerMid
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &middlewareMetadata, nil
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ func NewNetHTTPHandlerFunc(logger logger.Logger, h fasthttp.RequestHandler) http
|
|||
reqBody, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
logger.Errorf("error reading request body, %+v", err)
|
||||
|
||||
return
|
||||
}
|
||||
c.Request.SetBody(reqBody)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package nethttpadaptor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
@ -111,6 +112,7 @@ func TestNewNetHTTPHandlerFuncRequests(t *testing.T) {
|
|||
"Body is handled",
|
||||
func() *http.Request {
|
||||
body := strings.NewReader("test body!")
|
||||
|
||||
return httptest.NewRequest("GET", "http://localhost:8080/test/sub", body)
|
||||
},
|
||||
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
|
||||
|
@ -137,6 +139,7 @@ func TestNewNetHTTPHandlerFuncRequests(t *testing.T) {
|
|||
req.Header.Add("testHeaderKey1", "testHeaderValue1")
|
||||
req.Header.Add("testHeaderKey2", "testHeaderValue2")
|
||||
req.Header.Add("testHeaderKey3", "testHeaderValue3")
|
||||
|
||||
return req
|
||||
},
|
||||
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
|
||||
|
@ -167,6 +170,7 @@ func TestNewNetHTTPHandlerFuncRequests(t *testing.T) {
|
|||
req.Header.Add("testHeaderKey1", "testHeaderValue1")
|
||||
req.Header.Add("testHeaderKey1", "testHeaderValue2")
|
||||
req.Header.Add("testHeaderKey1", "testHeaderValue3")
|
||||
|
||||
return req
|
||||
},
|
||||
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
|
||||
|
@ -208,6 +212,7 @@ func TestNewNetHTTPHandlerFuncRequests(t *testing.T) {
|
|||
func() *http.Request {
|
||||
req := httptest.NewRequest("GET", "https://localhost:8080", nil)
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
return req
|
||||
},
|
||||
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
|
||||
|
@ -221,6 +226,7 @@ func TestNewNetHTTPHandlerFuncRequests(t *testing.T) {
|
|||
func() *http.Request {
|
||||
req := httptest.NewRequest("GET", "https://localhost:8080", nil)
|
||||
req.Header.Add("Content-Type", "multipart/form-data; boundary=test-boundary")
|
||||
|
||||
return req
|
||||
},
|
||||
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
|
||||
|
@ -234,6 +240,7 @@ func TestNewNetHTTPHandlerFuncRequests(t *testing.T) {
|
|||
func() *http.Request {
|
||||
req := httptest.NewRequest("GET", "https://localhost:8080", nil)
|
||||
req.Header.Add("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36")
|
||||
|
||||
return req
|
||||
},
|
||||
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
|
||||
|
@ -247,6 +254,7 @@ func TestNewNetHTTPHandlerFuncRequests(t *testing.T) {
|
|||
func() *http.Request {
|
||||
req := httptest.NewRequest("GET", "https://localhost:8080", nil)
|
||||
req.Header.Add("Referer", "testReferer")
|
||||
|
||||
return req
|
||||
},
|
||||
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
|
||||
|
@ -260,6 +268,7 @@ func TestNewNetHTTPHandlerFuncRequests(t *testing.T) {
|
|||
func() *http.Request {
|
||||
req := httptest.NewRequest("GET", "https://localhost:8080", nil)
|
||||
req.Header.Add("Authorization", "Basic YWxhZGRpbjpvcGVuc2VzYW1l") // b64(aladdin:opensesame)
|
||||
|
||||
return req
|
||||
},
|
||||
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
|
||||
|
@ -279,6 +288,7 @@ func TestNewNetHTTPHandlerFuncRequests(t *testing.T) {
|
|||
func() *http.Request {
|
||||
req := httptest.NewRequest("GET", "https://localhost:8080", nil)
|
||||
req.RemoteAddr = "1.1.1.1"
|
||||
|
||||
return req
|
||||
},
|
||||
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
|
||||
|
@ -290,7 +300,8 @@ func TestNewNetHTTPHandlerFuncRequests(t *testing.T) {
|
|||
{
|
||||
"nil body is handled",
|
||||
func() *http.Request {
|
||||
req, _ := http.NewRequest("GET", "https://localhost:8080", nil)
|
||||
req, _ := http.NewRequestWithContext(context.Background(), "GET", "https://localhost:8080", nil)
|
||||
|
||||
return req
|
||||
},
|
||||
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
|
||||
|
@ -302,7 +313,8 @@ func TestNewNetHTTPHandlerFuncRequests(t *testing.T) {
|
|||
{
|
||||
"proto headers are handled",
|
||||
func() *http.Request {
|
||||
req, _ := http.NewRequest("GET", "https://localhost:8080", nil)
|
||||
req, _ := http.NewRequestWithContext(context.Background(), "GET", "https://localhost:8080", nil)
|
||||
|
||||
return req
|
||||
},
|
||||
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
|
||||
|
|
|
@ -6,11 +6,10 @@
|
|||
package oauth2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"context"
|
||||
|
||||
"github.com/dapr/components-contrib/middleware"
|
||||
"github.com/fasthttp-contrib/sessions"
|
||||
"github.com/google/uuid"
|
||||
|
@ -27,6 +26,7 @@ type oAuth2MiddlewareMetadata struct {
|
|||
TokenURL string `json:"tokenURL"`
|
||||
AuthHeaderName string `json:"authHeaderName"`
|
||||
RedirectURL string `json:"redirectURL"`
|
||||
ForceHTTPS string `json:"forceHTTPS"`
|
||||
}
|
||||
|
||||
// NewOAuth2Middleware returns a new oAuth2 middleware
|
||||
|
@ -43,6 +43,7 @@ const (
|
|||
savedState = "auth-state"
|
||||
redirectPath = "redirect-url"
|
||||
codeParam = "code"
|
||||
https = "https://"
|
||||
)
|
||||
|
||||
// GetHandler retruns the HTTP handler provided by the middleware
|
||||
|
@ -68,6 +69,7 @@ func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.R
|
|||
if session.GetString(meta.AuthHeaderName) != "" {
|
||||
ctx.Request.Header.Add(meta.AuthHeaderName, session.GetString(meta.AuthHeaderName))
|
||||
h(ctx)
|
||||
|
||||
return
|
||||
}
|
||||
state := string(ctx.FormValue(stateParam))
|
||||
|
@ -81,6 +83,9 @@ func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.R
|
|||
} else {
|
||||
authState := session.GetString(savedState)
|
||||
redirectURL := session.GetString(redirectPath)
|
||||
if strings.EqualFold(meta.ForceHTTPS, "true") {
|
||||
redirectURL = https + string(ctx.Request.Host()) + redirectURL
|
||||
}
|
||||
if state != authState {
|
||||
ctx.Error("invalid state", fasthttp.StatusBadRequest)
|
||||
} else {
|
||||
|
@ -113,5 +118,6 @@ func (m *Middleware) getNativeMetadata(metadata middleware.Metadata) (*oAuth2Mid
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &middlewareMetadata, nil
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ func NewOAuth2ClientCredentialsMiddleware(logger logger.Logger) *Middleware {
|
|||
}
|
||||
// Default: set Token Provider to real implementation (we will overwrite it for unit testing)
|
||||
m.SetTokenProvider(m)
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
|
@ -63,6 +64,7 @@ func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.R
|
|||
meta, err := m.getNativeMetadata(metadata)
|
||||
if err != nil {
|
||||
m.log.Errorf("getNativeMetadata error, %s", err)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -70,13 +72,13 @@ func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.R
|
|||
return func(ctx *fasthttp.RequestCtx) {
|
||||
var headerValue string
|
||||
// Check if valid Token is in the cache
|
||||
var cacheKey = m.getCacheKey(meta)
|
||||
cacheKey := m.getCacheKey(meta)
|
||||
cachedToken, found := m.tokenCache.Get(cacheKey)
|
||||
|
||||
if !found {
|
||||
m.log.Debugf("Cached token not found, try get one")
|
||||
|
||||
var endpointParams, err = url.ParseQuery(meta.EndpointParamsQuery)
|
||||
endpointParams, err := url.ParseQuery(meta.EndpointParamsQuery)
|
||||
if err != nil {
|
||||
m.log.Errorf("Error parsing endpoint parameters, %s", err)
|
||||
endpointParams, _ = url.ParseQuery("")
|
||||
|
@ -94,6 +96,7 @@ func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.R
|
|||
token, tokenError := m.tokenProvider.GetToken(conf)
|
||||
if tokenError != nil {
|
||||
m.log.Errorf("Error acquiring token, %s", tokenError)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -101,6 +104,7 @@ func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.R
|
|||
m.log.Debugf("Duration in seconds %s, Expiry Time %s", tokenExpirationDuration, token.Expiry)
|
||||
if err != nil {
|
||||
m.log.Errorf("Error parsing duration string, %s", fmt.Sprintf("%ss", token.Expiry))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -167,6 +171,7 @@ func (m *Middleware) getCacheKey(meta *oAuth2ClientCredentialsMiddlewareMetadata
|
|||
hashedKey := sha256.New()
|
||||
key := strings.Join([]string{meta.ClientID, meta.Scopes}, "")
|
||||
hashedKey.Write([]byte(key))
|
||||
|
||||
return fmt.Sprintf("%x", hashedKey.Sum(nil))
|
||||
}
|
||||
|
||||
|
@ -178,5 +183,6 @@ func (m *Middleware) SetTokenProvider(tokenProvider TokenProviderInterface) {
|
|||
// GetToken returns a token from the current OAuth2 ClientCredentials Configuration
|
||||
func (m *Middleware) GetToken(conf *clientcredentials.Config) (*oauth2.Token, error) {
|
||||
tokenSource := conf.TokenSource(context.Background())
|
||||
|
||||
return tokenSource.Token()
|
||||
}
|
||||
|
|
|
@ -9,10 +9,9 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/dapr/components-contrib/middleware"
|
||||
mock "github.com/dapr/components-contrib/middleware/http/oauth2clientcredentials/mocks"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
|
||||
"github.com/dapr/components-contrib/middleware"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
package opa
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/dapr/components-contrib/middleware"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
"github.com/open-policy-agent/opa/rego"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
type middlewareMetadata struct {
|
||||
Rego string `json:"rego"`
|
||||
DefaultStatus int `json:"defaultStatus,omitempty"`
|
||||
IncludedHeaders string `json:"includedHeaders,omitempty"`
|
||||
}
|
||||
|
||||
// NewMiddleware returns a new Open Policy Agent middleware
|
||||
func NewMiddleware(logger logger.Logger) *Middleware {
|
||||
return &Middleware{logger: logger}
|
||||
}
|
||||
|
||||
// Middleware is an OPA middleware
|
||||
type Middleware struct {
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
// RegoResult is the expected result from rego policy
|
||||
type RegoResult struct {
|
||||
Allow bool `json:"allow"`
|
||||
AdditionalHeaders map[string]string `json:"additional_headers,omitempty"`
|
||||
StatusCode int `json:"status_code,omitempty"`
|
||||
}
|
||||
|
||||
const opaErrorHeaderKey = "x-dapr-opa-error"
|
||||
|
||||
var (
|
||||
errOpaNoResult = errors.New("received no results back from rego policy. Are you setting data.http.allow?")
|
||||
errOpaInvalidResultType = errors.New("got an invalid type back from repo policy. Only a boolean or map is valid")
|
||||
)
|
||||
|
||||
// GetHandler returns the HTTP handler provided by the middleware
|
||||
func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.RequestHandler) fasthttp.RequestHandler, error) {
|
||||
meta, err := m.getNativeMetadata(metadata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
query, err := rego.New(
|
||||
rego.Query("result = data.http.allow"),
|
||||
rego.Module("inline.rego", meta.Rego),
|
||||
).PrepareForEval(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return func(h fasthttp.RequestHandler) fasthttp.RequestHandler {
|
||||
return func(ctx *fasthttp.RequestCtx) {
|
||||
if handled := m.evalRequest(ctx, meta, &query); handled {
|
||||
return
|
||||
}
|
||||
h(ctx)
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *Middleware) evalRequest(ctx *fasthttp.RequestCtx, meta *middlewareMetadata, query *rego.PreparedEvalQuery) bool {
|
||||
headers := map[string]string{}
|
||||
allowedHeaders := strings.Split(meta.IncludedHeaders, ",")
|
||||
ctx.Request.Header.VisitAll(func(key, value []byte) {
|
||||
for _, allowedHeader := range allowedHeaders {
|
||||
buf := []byte("")
|
||||
result := fasthttp.AppendNormalizedHeaderKeyBytes(buf, []byte(allowedHeader))
|
||||
normalizedHeader := result[0:]
|
||||
if bytes.Equal(key, normalizedHeader) {
|
||||
headers[string(key)] = string(value)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
queryArgs := map[string][]string{}
|
||||
ctx.QueryArgs().VisitAll(func(key, value []byte) {
|
||||
if val, ok := queryArgs[string(key)]; ok {
|
||||
queryArgs[string(key)] = append(val, string(value))
|
||||
} else {
|
||||
queryArgs[string(key)] = []string{string(value)}
|
||||
}
|
||||
})
|
||||
|
||||
path := string(ctx.Path())
|
||||
pathParts := strings.Split(strings.Trim(path, "/"), "/")
|
||||
input := map[string]interface{}{
|
||||
"request": map[string]interface{}{
|
||||
"method": string(ctx.Method()),
|
||||
"path": path,
|
||||
"path_parts": pathParts,
|
||||
"raw_query": string(ctx.QueryArgs().QueryString()),
|
||||
"query": queryArgs,
|
||||
"headers": headers,
|
||||
"scheme": string(ctx.Request.URI().Scheme()),
|
||||
},
|
||||
}
|
||||
|
||||
results, err := query.Eval(context.TODO(), rego.EvalInput(input))
|
||||
if err != nil {
|
||||
m.opaError(ctx, meta, err)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
if len(results) == 0 {
|
||||
m.opaError(ctx, meta, errOpaNoResult)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
return m.handleRegoResult(ctx, meta, results[0].Bindings["result"])
|
||||
}
|
||||
|
||||
// handleRegoResult takes the in process request and open policy agent evaluation result
|
||||
// and maps it the appropriate response or headers.
|
||||
// It returns true if the request should continue, or false if a response should be immediately returned.
|
||||
func (m *Middleware) handleRegoResult(ctx *fasthttp.RequestCtx, meta *middlewareMetadata, result interface{}) bool {
|
||||
if allowed, ok := result.(bool); ok {
|
||||
if !allowed {
|
||||
ctx.Error(fasthttp.StatusMessage(meta.DefaultStatus), meta.DefaultStatus)
|
||||
}
|
||||
|
||||
return allowed
|
||||
}
|
||||
|
||||
if _, ok := result.(map[string]interface{}); !ok {
|
||||
m.opaError(ctx, meta, errOpaInvalidResultType)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Is it expensive to marshal back and forth? Should we just manually pull out properties?
|
||||
marshaled, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
m.opaError(ctx, meta, err)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
regoResult := RegoResult{
|
||||
// By default, a non-allowed request with return a 403 response.
|
||||
StatusCode: meta.DefaultStatus,
|
||||
AdditionalHeaders: make(map[string]string),
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(marshaled, ®oResult); err != nil {
|
||||
m.opaError(ctx, meta, err)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// If the result isn't allowed, set the response status and
|
||||
// apply the additional headers to the response.
|
||||
// Otherwise, set the headers on the ongoing request (overriding as necessary)
|
||||
if !regoResult.Allow {
|
||||
ctx.Error(fasthttp.StatusMessage(regoResult.StatusCode), regoResult.StatusCode)
|
||||
for key, value := range regoResult.AdditionalHeaders {
|
||||
ctx.Response.Header.Set(key, value)
|
||||
}
|
||||
} else {
|
||||
for key, value := range regoResult.AdditionalHeaders {
|
||||
ctx.Request.Header.Set(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
return regoResult.Allow
|
||||
}
|
||||
|
||||
func (m *Middleware) opaError(ctx *fasthttp.RequestCtx, meta *middlewareMetadata, err error) {
|
||||
ctx.Error(fasthttp.StatusMessage(meta.DefaultStatus), meta.DefaultStatus)
|
||||
ctx.Response.Header.Set(opaErrorHeaderKey, "true")
|
||||
m.logger.Warnf("Error procesing rego policy: %v", err)
|
||||
}
|
||||
|
||||
func (m *Middleware) getNativeMetadata(metadata middleware.Metadata) (*middlewareMetadata, error) {
|
||||
b, err := json.Marshal(metadata.Properties)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
meta := middlewareMetadata{
|
||||
DefaultStatus: 403,
|
||||
}
|
||||
err = json.Unmarshal(b, &meta)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &meta, nil
|
||||
}
|
|
@ -0,0 +1,234 @@
|
|||
package opa
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/dapr/components-contrib/middleware"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
fh "github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
func mockedRequestHandler(ctx *fh.RequestCtx) {}
|
||||
|
||||
type RequestConfiguator func(*fh.RequestCtx)
|
||||
|
||||
func TestOpaPolicy(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
meta middleware.Metadata
|
||||
req RequestConfiguator
|
||||
status int
|
||||
headers *[][]string
|
||||
shouldHandlerError bool
|
||||
shouldRegoError bool
|
||||
}{
|
||||
"allow": {
|
||||
meta: middleware.Metadata{
|
||||
Properties: map[string]string{
|
||||
"rego": `
|
||||
package http
|
||||
allow = true`,
|
||||
},
|
||||
},
|
||||
status: 200,
|
||||
},
|
||||
"deny": {
|
||||
meta: middleware.Metadata{
|
||||
Properties: map[string]string{
|
||||
"rego": `
|
||||
package http
|
||||
allow = false`,
|
||||
},
|
||||
},
|
||||
status: 403,
|
||||
},
|
||||
"status": {
|
||||
meta: middleware.Metadata{
|
||||
Properties: map[string]string{
|
||||
"rego": `
|
||||
package http
|
||||
allow = {
|
||||
"allow": false,
|
||||
"status_code": 301
|
||||
}`,
|
||||
},
|
||||
},
|
||||
status: 301,
|
||||
},
|
||||
"add redirect": {
|
||||
meta: middleware.Metadata{
|
||||
Properties: map[string]string{
|
||||
"rego": `
|
||||
package http
|
||||
allow = {
|
||||
"allow": false,
|
||||
"status_code": 301,
|
||||
"additional_headers": { "location": "https://my.site/login" }
|
||||
}`,
|
||||
},
|
||||
},
|
||||
status: 301,
|
||||
headers: &[][]string{
|
||||
{"location", "https://my.site/login"},
|
||||
},
|
||||
},
|
||||
"add headers": {
|
||||
meta: middleware.Metadata{
|
||||
Properties: map[string]string{
|
||||
"rego": `
|
||||
package http
|
||||
allow = {
|
||||
"allow": false,
|
||||
"status_code": 301,
|
||||
"additional_headers": { "x-key": "abc" }
|
||||
}`,
|
||||
},
|
||||
},
|
||||
status: 301,
|
||||
headers: &[][]string{
|
||||
{"x-key", "abc"},
|
||||
},
|
||||
},
|
||||
"allow with path": {
|
||||
meta: middleware.Metadata{
|
||||
Properties: map[string]string{
|
||||
"rego": `
|
||||
package http
|
||||
default allow = true
|
||||
|
||||
allow = { "status_code": 403 } {
|
||||
input.request.path_parts[0] = "forbidden"
|
||||
}
|
||||
`,
|
||||
},
|
||||
},
|
||||
req: func(ctx *fh.RequestCtx) {
|
||||
ctx.Request.SetHost("https://my.site")
|
||||
ctx.Request.URI().SetPath("/allowed")
|
||||
},
|
||||
status: 200,
|
||||
},
|
||||
"deny with path": {
|
||||
meta: middleware.Metadata{
|
||||
Properties: map[string]string{
|
||||
"rego": `
|
||||
package http
|
||||
default allow = true
|
||||
|
||||
allow = { "status_code": 403 } {
|
||||
input.request.path_parts[0] = "forbidden"
|
||||
}
|
||||
`,
|
||||
},
|
||||
},
|
||||
req: func(ctx *fh.RequestCtx) {
|
||||
ctx.Request.SetHost("https://my.site")
|
||||
ctx.Request.URI().SetPath("/forbidden")
|
||||
},
|
||||
status: 403,
|
||||
},
|
||||
"allow when header not included": {
|
||||
meta: middleware.Metadata{
|
||||
Properties: map[string]string{
|
||||
"rego": `
|
||||
package http
|
||||
default allow = true
|
||||
|
||||
allow = { "status_code": 403 } {
|
||||
input.request.headers["x-bad-header"] = "1"
|
||||
}
|
||||
`,
|
||||
},
|
||||
},
|
||||
req: func(ctx *fh.RequestCtx) {
|
||||
ctx.Request.SetHost("https://my.site")
|
||||
ctx.Request.Header.Add("x-bad-header", "1")
|
||||
},
|
||||
status: 200,
|
||||
},
|
||||
"deny when header included": {
|
||||
meta: middleware.Metadata{
|
||||
Properties: map[string]string{
|
||||
"rego": `
|
||||
package http
|
||||
default allow = true
|
||||
|
||||
allow = { "status_code": 403 } {
|
||||
input.request.headers["X-Bad-Header"] = "1"
|
||||
}
|
||||
`,
|
||||
"includedHeaders": "x-bad-header",
|
||||
},
|
||||
},
|
||||
req: func(ctx *fh.RequestCtx) {
|
||||
ctx.Request.SetHost("https://my.site")
|
||||
ctx.Request.Header.Add("x-bad-header", "1")
|
||||
},
|
||||
status: 403,
|
||||
},
|
||||
"err on no rego": {
|
||||
meta: middleware.Metadata{
|
||||
Properties: map[string]string{},
|
||||
},
|
||||
shouldHandlerError: true,
|
||||
},
|
||||
"err on bad allow": {
|
||||
meta: middleware.Metadata{
|
||||
Properties: map[string]string{
|
||||
"rego": `
|
||||
package http
|
||||
allow = 1`,
|
||||
},
|
||||
},
|
||||
shouldRegoError: true,
|
||||
},
|
||||
"err on bad package": {
|
||||
meta: middleware.Metadata{
|
||||
Properties: map[string]string{
|
||||
"rego": `
|
||||
package http.authz
|
||||
allow = true`,
|
||||
},
|
||||
},
|
||||
shouldRegoError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
log := logger.NewLogger("opa.test")
|
||||
opaMiddleware := NewMiddleware(log)
|
||||
handler, err := opaMiddleware.GetHandler(test.meta)
|
||||
|
||||
if test.shouldHandlerError {
|
||||
require.Error(t, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
var reqCtx fh.RequestCtx
|
||||
if test.req != nil {
|
||||
test.req(&reqCtx)
|
||||
}
|
||||
handler(mockedRequestHandler)(&reqCtx)
|
||||
|
||||
if test.shouldRegoError {
|
||||
assert.Equal(t, 403, reqCtx.Response.StatusCode())
|
||||
assert.Equal(t, "true", string(reqCtx.Response.Header.Peek(opaErrorHeaderKey)))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, test.status, reqCtx.Response.StatusCode())
|
||||
|
||||
if test.headers != nil {
|
||||
for _, header := range *test.headers {
|
||||
assert.Equal(t, header[1], string(reqCtx.Response.Header.Peek(header[0])))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -51,6 +51,7 @@ func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.R
|
|||
return func(h fasthttp.RequestHandler) fasthttp.RequestHandler {
|
||||
limitHandler := tollbooth.LimitFuncHandler(limiter, nethttpadaptor.NewNetHTTPHandlerFunc(m.logger, h))
|
||||
wrappedHandler := fasthttpadaptor.NewFastHTTPHandlerFunc(limitHandler.ServeHTTP)
|
||||
|
||||
return func(ctx *fasthttp.RequestCtx) {
|
||||
wrappedHandler(ctx)
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ func (m *resolver) Init(metadata nameresolution.Metadata) error {
|
|||
var hostAddress string
|
||||
var ok bool
|
||||
|
||||
var props = metadata.Properties
|
||||
props := metadata.Properties
|
||||
|
||||
if id, ok = props[nameresolution.MDNSInstanceName]; !ok {
|
||||
return errors.New("name is missing")
|
||||
|
@ -83,6 +83,7 @@ func (m *resolver) registerMDNS(id string, ips []string, port int) error {
|
|||
if err != nil {
|
||||
started <- false
|
||||
m.logger.Errorf("error from zeroconf register: %s", err)
|
||||
|
||||
return
|
||||
}
|
||||
started <- true
|
||||
|
@ -96,6 +97,7 @@ func (m *resolver) registerMDNS(id string, ips []string, port int) error {
|
|||
}()
|
||||
|
||||
<-started
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -127,6 +129,7 @@ func (m *resolver) ResolveID(req nameresolution.ResolveRequest) (string, error)
|
|||
|
||||
// cancel timeout because it found the service
|
||||
cancel()
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -136,6 +139,7 @@ func (m *resolver) ResolveID(req nameresolution.ResolveRequest) (string, error)
|
|||
if err = resolver.Browse(ctx, req.ID, "local.", entries); err != nil {
|
||||
// cancel context
|
||||
cancel()
|
||||
|
||||
return "", fmt.Errorf("failed to browse: %s", err.Error())
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
)
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
var tests = []struct {
|
||||
tests := []struct {
|
||||
missingProp string
|
||||
props map[string]string
|
||||
}{
|
||||
|
|
|
@ -9,14 +9,12 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
aws_auth "github.com/dapr/components-contrib/authentication/aws"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
|
||||
sns "github.com/aws/aws-sdk-go/service/sns"
|
||||
sqs "github.com/aws/aws-sdk-go/service/sqs"
|
||||
aws_auth "github.com/dapr/components-contrib/authentication/aws"
|
||||
"github.com/dapr/components-contrib/pubsub"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
)
|
||||
|
||||
type snsSqs struct {
|
||||
|
@ -25,12 +23,13 @@ type snsSqs struct {
|
|||
// key is the hashed topic name, value is the actual topic name
|
||||
topicHash map[string]string
|
||||
// key is the topic name, value holds the ARN of the queue and its url
|
||||
queues map[string]*sqsQueueInfo
|
||||
awsAcctID string
|
||||
snsClient *sns.SNS
|
||||
sqsClient *sqs.SQS
|
||||
metadata *snsSqsMetadata
|
||||
logger logger.Logger
|
||||
queues map[string]*sqsQueueInfo
|
||||
awsAcctID string
|
||||
snsClient *sns.SNS
|
||||
sqsClient *sqs.SQS
|
||||
metadata *snsSqsMetadata
|
||||
logger logger.Logger
|
||||
subscriptions []*string
|
||||
}
|
||||
|
||||
type sqsQueueInfo struct {
|
||||
|
@ -69,15 +68,15 @@ const (
|
|||
)
|
||||
|
||||
func NewSnsSqs(l logger.Logger) pubsub.PubSub {
|
||||
return &snsSqs{logger: l}
|
||||
return &snsSqs{logger: l, subscriptions: []*string{}}
|
||||
}
|
||||
|
||||
func parseInt64(input string, propertyName string) (int64, error) {
|
||||
number, err := strconv.Atoi(input)
|
||||
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf("parsing %s failed with: %v", propertyName, err)
|
||||
}
|
||||
|
||||
return int64(number), nil
|
||||
}
|
||||
|
||||
|
@ -86,6 +85,7 @@ func parseInt64(input string, propertyName string) (int64, error) {
|
|||
func nameToHash(name string) string {
|
||||
h := sha256.New()
|
||||
h.Write([]byte(name))
|
||||
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,6 @@ func (s *snsSqs) getSnsSqsMetatdata(metadata pubsub.Metadata) (*snsSqsMetadata,
|
|||
md.messageVisibilityTimeout = 10
|
||||
} else {
|
||||
timeout, err := parseInt64(val, "messageVisibilityTimeout")
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -148,7 +147,6 @@ func (s *snsSqs) getSnsSqsMetatdata(metadata pubsub.Metadata) (*snsSqsMetadata,
|
|||
md.messageRetryLimit = 10
|
||||
} else {
|
||||
retryLimit, err := parseInt64(val, "messageRetryLimit")
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -164,7 +162,6 @@ func (s *snsSqs) getSnsSqsMetatdata(metadata pubsub.Metadata) (*snsSqsMetadata,
|
|||
md.messageWaitTimeSeconds = 1
|
||||
} else {
|
||||
waitTime, err := parseInt64(val, "messageWaitTimeSeconds")
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -180,7 +177,6 @@ func (s *snsSqs) getSnsSqsMetatdata(metadata pubsub.Metadata) (*snsSqsMetadata,
|
|||
md.messageMaxNumber = 10
|
||||
} else {
|
||||
maxNumber, err := parseInt64(val, "messageMaxNumber")
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -199,7 +195,6 @@ func (s *snsSqs) getSnsSqsMetatdata(metadata pubsub.Metadata) (*snsSqsMetadata,
|
|||
|
||||
func (s *snsSqs) Init(metadata pubsub.Metadata) error {
|
||||
md, err := s.getSnsSqsMetatdata(metadata)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -218,6 +213,7 @@ func (s *snsSqs) Init(metadata pubsub.Metadata) error {
|
|||
}
|
||||
s.snsClient = sns.New(sess)
|
||||
s.sqsClient = sqs.New(sess)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -227,7 +223,6 @@ func (s *snsSqs) createTopic(topic string) (string, string, error) {
|
|||
Name: aws.String(hashedName),
|
||||
Tags: []*sns.Tag{{Key: aws.String(awsSnsTopicNameKey), Value: aws.String(topic)}},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
@ -242,15 +237,16 @@ func (s *snsSqs) getOrCreateTopic(topic string) (string, error) {
|
|||
|
||||
if ok {
|
||||
s.logger.Debugf("Found existing topic ARN for topic %s: %s", topic, topicArn)
|
||||
|
||||
return topicArn, nil
|
||||
}
|
||||
|
||||
s.logger.Debugf("No topic ARN found for %s\n Creating topic instead.", topic)
|
||||
|
||||
topicArn, hashedName, err := s.createTopic(topic)
|
||||
|
||||
if err != nil {
|
||||
s.logger.Errorf("error creating new topic %s: %v", topic, err)
|
||||
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
@ -266,7 +262,6 @@ func (s *snsSqs) createQueue(queueName string) (*sqsQueueInfo, error) {
|
|||
QueueName: aws.String(nameToHash(queueName)),
|
||||
Tags: map[string]*string{awsSqsQueueNameKey: aws.String(queueName)},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -275,7 +270,6 @@ func (s *snsSqs) createQueue(queueName string) (*sqsQueueInfo, error) {
|
|||
AttributeNames: []*string{aws.String("QueueArn")},
|
||||
QueueUrl: createQueueResponse.QueueUrl,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
s.logger.Errorf("error fetching queue attributes for %s: %v", queueName, err)
|
||||
}
|
||||
|
@ -310,15 +304,16 @@ func (s *snsSqs) getOrCreateQueue(queueName string) (*sqsQueueInfo, error) {
|
|||
|
||||
if ok {
|
||||
s.logger.Debugf("Found queue arn for %s: %s", queueName, queueArn)
|
||||
|
||||
return queueArn, nil
|
||||
}
|
||||
// creating queues is idempotent, the names serve as unique keys among a given region
|
||||
s.logger.Debugf("No queue arn found for %s\nCreating queue", queueName)
|
||||
|
||||
queueInfo, err := s.createQueue(queueName)
|
||||
|
||||
if err != nil {
|
||||
s.logger.Errorf("Error creating queue %s: %v", queueName, err)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -329,7 +324,6 @@ func (s *snsSqs) getOrCreateQueue(queueName string) (*sqsQueueInfo, error) {
|
|||
|
||||
func (s *snsSqs) Publish(req *pubsub.PublishRequest) error {
|
||||
topicArn, err := s.getOrCreateTopic(req.Topic)
|
||||
|
||||
if err != nil {
|
||||
s.logger.Errorf("error getting topic ARN for %s: %v", req.Topic, err)
|
||||
}
|
||||
|
@ -342,6 +336,7 @@ func (s *snsSqs) Publish(req *pubsub.PublishRequest) error {
|
|||
|
||||
if err != nil {
|
||||
s.logger.Errorf("error publishing topic %s with topic ARN %s: %v", req.Topic, topicArn, err)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -376,7 +371,6 @@ func (s *snsSqs) handleMessage(message *sqs.Message, queueInfo *sqsQueueInfo, ha
|
|||
}
|
||||
|
||||
recvCountInt, err := strconv.ParseInt(*recvCount, 10, 32)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing ApproximateReceiveCount from message: %v", message)
|
||||
}
|
||||
|
@ -428,15 +422,16 @@ func (s *snsSqs) consumeSubscription(queueInfo *sqsQueueInfo, handler pubsub.Han
|
|||
VisibilityTimeout: aws.Int64(s.metadata.messageVisibilityTimeout),
|
||||
WaitTimeSeconds: aws.Int64(s.metadata.messageWaitTimeSeconds),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
s.logger.Errorf("error consuming topic: %v", err)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// retry receiving messages
|
||||
if len(messageResponse.Messages) < 1 {
|
||||
s.logger.Debug("No messages received, requesting again")
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -457,17 +452,17 @@ func (s *snsSqs) Subscribe(req pubsub.SubscribeRequest, handler pubsub.Handler)
|
|||
// these should be idempotent
|
||||
// queues should not be created if they exist
|
||||
topicArn, err := s.getOrCreateTopic(req.Topic)
|
||||
|
||||
if err != nil {
|
||||
s.logger.Errorf("error getting topic ARN for %s: %v", req.Topic, err)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// this is the ID of the application, it is supplied via runtime as "consumerID"
|
||||
queueInfo, err := s.getOrCreateQueue(s.metadata.sqsQueueName)
|
||||
|
||||
if err != nil {
|
||||
s.logger.Errorf("error retrieving SQS queue: %v", err)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -479,15 +474,26 @@ func (s *snsSqs) Subscribe(req pubsub.SubscribeRequest, handler pubsub.Handler)
|
|||
ReturnSubscriptionArn: nil,
|
||||
TopicArn: &topicArn,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
s.logger.Errorf("error subscribing to topic %s: %v", req.Topic, err)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
s.subscriptions = append(s.subscriptions, subscribeOutput.SubscriptionArn)
|
||||
s.logger.Debugf("Subscribed to topic %s: %v", req.Topic, subscribeOutput)
|
||||
|
||||
s.consumeSubscription(queueInfo, handler)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *snsSqs) Close() error {
|
||||
for _, sub := range s.subscriptions {
|
||||
s.snsClient.Unsubscribe(&sns.UnsubscribeInput{
|
||||
SubscriptionArn: sub,
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -103,12 +103,12 @@ func (aeh *AzureEventHubs) Init(metadata pubsub.Metadata) error {
|
|||
}
|
||||
aeh.metadata = m
|
||||
hub, err := eventhub.NewHubFromConnectionString(aeh.metadata.connectionString)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to connect to azure event hubs: %v", err)
|
||||
}
|
||||
|
||||
aeh.hub = hub
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -118,6 +118,7 @@ func (aeh *AzureEventHubs) Publish(req *pubsub.PublishRequest) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("error from publish: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -134,7 +135,6 @@ func (aeh *AzureEventHubs) Subscribe(req pubsub.SubscribeRequest, handler pubsub
|
|||
}
|
||||
|
||||
processor, err := eph.NewFromConnectionString(context.Background(), aeh.metadata.connectionString, leaserCheckpointer, leaserCheckpointer, eph.WithNoBanner(), eph.WithConsumerGroup(aeh.metadata.consumerGroup))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -154,3 +154,7 @@ func (aeh *AzureEventHubs) Subscribe(req pubsub.SubscribeRequest, handler pubsub
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (aeh *AzureEventHubs) Close() error {
|
||||
return aeh.hub.Close(context.TODO())
|
||||
}
|
||||
|
|
|
@ -57,7 +57,8 @@ func TestParseEventHubsMetadata(t *testing.T) {
|
|||
"missing storageContainerName",
|
||||
map[string]string{"consumerID": "fake", "connectionString": "fake", "storageAccountName": "name", "storageAccountKey": "key"},
|
||||
missingStorageContainerNameErrorMsg,
|
||||
}}
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range invalidConfigTestCases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
|
|
|
@ -51,16 +51,18 @@ const (
|
|||
type handle = struct{}
|
||||
|
||||
type azureServiceBus struct {
|
||||
metadata metadata
|
||||
namespace *azservicebus.Namespace
|
||||
topicManager *azservicebus.TopicManager
|
||||
logger logger.Logger
|
||||
metadata metadata
|
||||
namespace *azservicebus.Namespace
|
||||
topicManager *azservicebus.TopicManager
|
||||
logger logger.Logger
|
||||
subscriptions []*subscription
|
||||
}
|
||||
|
||||
// NewAzureServiceBus returns a new Azure ServiceBus pub-sub implementation
|
||||
func NewAzureServiceBus(logger logger.Logger) pubsub.PubSub {
|
||||
return &azureServiceBus{
|
||||
logger: logger,
|
||||
logger: logger,
|
||||
subscriptions: []*subscription{},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,6 +204,7 @@ func (a *azureServiceBus) Init(metadata pubsub.Metadata) error {
|
|||
}
|
||||
|
||||
a.topicManager = a.namespace.NewTopicManager()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -226,6 +229,7 @@ func (a *azureServiceBus) Publish(req *pubsub.PublishRequest) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -258,6 +262,7 @@ func (a *azureServiceBus) Subscribe(req pubsub.SubscribeRequest, handler pubsub.
|
|||
select {
|
||||
case <-reconnCtx.Done():
|
||||
a.logger.Debugf("Reconnect context for topic %s is done", req.Topic)
|
||||
|
||||
return
|
||||
case <-time.After(2 * time.Minute):
|
||||
attempts := readAttemptsStale()
|
||||
|
@ -274,6 +279,7 @@ func (a *azureServiceBus) Subscribe(req pubsub.SubscribeRequest, handler pubsub.
|
|||
topic, err := a.namespace.NewTopic(req.Topic)
|
||||
if err != nil {
|
||||
a.logger.Errorf("%s could not instantiate topic %s, %s", errorMessagePrefix, req.Topic, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -284,10 +290,11 @@ func (a *azureServiceBus) Subscribe(req pubsub.SubscribeRequest, handler pubsub.
|
|||
subEntity, err := topic.NewSubscription(subID, opts...)
|
||||
if err != nil {
|
||||
a.logger.Errorf("%s could not instantiate subscription %s for topic %s", errorMessagePrefix, subID, req.Topic)
|
||||
|
||||
return
|
||||
}
|
||||
sub := newSubscription(req.Topic, subEntity, a.metadata.MaxConcurrentHandlers, a.logger)
|
||||
|
||||
a.subscriptions = append(a.subscriptions, sub)
|
||||
// ReceiveAndBlock will only return with an error
|
||||
// that it cannot handle internally. The subscription
|
||||
// connection is closed when this method returns.
|
||||
|
@ -310,6 +317,7 @@ func (a *azureServiceBus) Subscribe(req pubsub.SubscribeRequest, handler pubsub.
|
|||
attempts := readAttemptsStale()
|
||||
if attempts == 0 {
|
||||
a.logger.Errorf("Subscription to topic %s lost connection, unable to recover after %d attempts", sub.topic, maxReconnAttempts)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -334,6 +342,7 @@ func (a *azureServiceBus) ensureTopic(topic string) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -359,6 +368,7 @@ func (a *azureServiceBus) ensureSubscription(name string, topic string) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -373,6 +383,7 @@ func (a *azureServiceBus) getTopicEntity(topic string) (*azservicebus.TopicEntit
|
|||
if err != nil && !azservicebus.IsErrNotFound(err) {
|
||||
return nil, fmt.Errorf("%s could not get topic %s, %s", errorMessagePrefix, topic, err)
|
||||
}
|
||||
|
||||
return topicEntity, nil
|
||||
}
|
||||
|
||||
|
@ -383,6 +394,7 @@ func (a *azureServiceBus) createTopicEntity(topic string) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("%s could not put topic %s, %s", errorMessagePrefix, topic, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -393,6 +405,7 @@ func (a *azureServiceBus) getSubscriptionEntity(mgr *azservicebus.SubscriptionMa
|
|||
if err != nil && !azservicebus.IsErrNotFound(err) {
|
||||
return nil, fmt.Errorf("%s could not get subscription %s, %s", errorMessagePrefix, subscription, err)
|
||||
}
|
||||
|
||||
return entity, nil
|
||||
}
|
||||
|
||||
|
@ -409,6 +422,7 @@ func (a *azureServiceBus) createSubscriptionEntity(mgr *azservicebus.Subscriptio
|
|||
if err != nil {
|
||||
return fmt.Errorf("%s could not put subscription %s, %s", errorMessagePrefix, subscription, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -426,13 +440,23 @@ func (a *azureServiceBus) createSubscriptionManagementOptions() ([]azservicebus.
|
|||
if a.metadata.AutoDeleteOnIdleInSec != nil {
|
||||
opts = append(opts, subscriptionManagementOptionsWithAutoDeleteOnIdle(a.metadata.AutoDeleteOnIdleInSec))
|
||||
}
|
||||
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
func (a *azureServiceBus) Close() error {
|
||||
for _, s := range a.subscriptions {
|
||||
s.close(context.TODO())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func subscriptionManagementOptionsWithMaxDeliveryCount(maxDeliveryCount *int) azservicebus.SubscriptionManagementOption {
|
||||
return func(d *azservicebus.SubscriptionDescription) error {
|
||||
mdc := int32(*maxDeliveryCount)
|
||||
d.MaxDeliveryCount = &mdc
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -441,6 +465,7 @@ func subscriptionManagementOptionsWithAutoDeleteOnIdle(durationInSec *int) azser
|
|||
return func(d *azservicebus.SubscriptionDescription) error {
|
||||
duration := fmt.Sprintf("PT%dS", *durationInSec)
|
||||
d.AutoDeleteOnIdle = &duration
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -449,6 +474,7 @@ func subscriptionManagementOptionsWithDefaultMessageTimeToLive(durationInSec *in
|
|||
return func(d *azservicebus.SubscriptionDescription) error {
|
||||
duration := fmt.Sprintf("PT%dS", *durationInSec)
|
||||
d.DefaultMessageTimeToLive = &duration
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -457,6 +483,7 @@ func subscriptionManagementOptionsWithLockDuration(durationInSec *int) azservice
|
|||
return func(d *azservicebus.SubscriptionDescription) error {
|
||||
duration := fmt.Sprintf("PT%dS", *durationInSec)
|
||||
d.LockDuration = &duration
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,8 @@ package servicebus
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/dapr/components-contrib/pubsub"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -55,12 +55,14 @@ func (s *subscription) ReceiveAndBlock(ctx context.Context, handler pubsub.Handl
|
|||
shouldRenewLocks := lockRenewalInSec > 0
|
||||
if !shouldRenewLocks {
|
||||
s.logger.Debugf("Lock renewal for topic %s disabled", s.topic)
|
||||
|
||||
return
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
s.logger.Debugf("Lock renewal context for topic %s done", s.topic)
|
||||
|
||||
return
|
||||
case <-time.After(time.Second * time.Duration(lockRenewalInSec)):
|
||||
s.tryRenewLocks()
|
||||
|
@ -82,6 +84,7 @@ func (s *subscription) ReceiveAndBlock(ctx context.Context, handler pubsub.Handl
|
|||
select {
|
||||
case <-ctx.Done():
|
||||
s.logger.Debugf("Receive context for topic %s done", s.topic)
|
||||
|
||||
return ctx.Err()
|
||||
case <-time.After(time.Second * time.Duration(maxActiveMessagesRecoveryInSec)):
|
||||
continue
|
||||
|
@ -151,6 +154,7 @@ func (s *subscription) asyncWrapper(handlerFunc azservicebus.HandlerFunc) azserv
|
|||
select {
|
||||
case <-ctx.Done():
|
||||
s.logger.Debugf("Message context done for %s on topic %s", msg.ID, s.topic)
|
||||
|
||||
return
|
||||
case <-s.handleChan: // Take or wait on a free handle before getting a new message
|
||||
s.logger.Debugf("Taken message handle for %s on topic %s", msg.ID, s.topic)
|
||||
|
@ -168,6 +172,7 @@ func (s *subscription) asyncWrapper(handlerFunc azservicebus.HandlerFunc) azserv
|
|||
s.logger.Errorf("%s error handling message %s on topic '%s', %s", errorMessagePrefix, msg.ID, s.topic, err)
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -178,6 +183,7 @@ func (s *subscription) tryRenewLocks() {
|
|||
s.mu.RUnlock()
|
||||
if activeMessageLen == 0 {
|
||||
s.logger.Debugf("No active messages require lock renewal for topic %s", s.topic)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -202,16 +208,19 @@ func (s *subscription) receiveMessage(ctx context.Context, handler azservicebus.
|
|||
if err := s.entity.ReceiveOne(ctx, handler); err != nil {
|
||||
return fmt.Errorf("%s error receiving message on topic %s, %s", errorMessagePrefix, s.topic, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *subscription) abandonMessage(ctx context.Context, m *azservicebus.Message) error {
|
||||
s.logger.Debugf("Abandoning message %s on topic %s", m.ID, s.topic)
|
||||
|
||||
return m.Abandon(ctx)
|
||||
}
|
||||
|
||||
func (s *subscription) completeMessage(ctx context.Context, m *azservicebus.Message) error {
|
||||
s.logger.Debugf("Completing message %s on topic %s", m.ID, s.topic)
|
||||
|
||||
return m.Complete(ctx)
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ const (
|
|||
DefaultCloudEventType = "com.dapr.event.sent"
|
||||
// CloudEventsSpecVersion is the specversion used by Dapr for the cloud events implementation
|
||||
CloudEventsSpecVersion = "1.0"
|
||||
//ContentType is the Cloud Events HTTP content type
|
||||
// ContentType is the Cloud Events HTTP content type
|
||||
ContentType = "application/cloudevents+json"
|
||||
// DefaultCloudEventSource is the default event source
|
||||
DefaultCloudEventSource = "Dapr"
|
||||
|
@ -111,5 +111,6 @@ func getStrVal(m map[string]interface{}, key string) string {
|
|||
return s
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -55,15 +55,17 @@ func (g *GCPPubSub) Init(meta pubsub.Metadata) error {
|
|||
|
||||
g.client = pubsubClient
|
||||
g.metadata = &pubsubMeta
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *GCPPubSub) parseMetadata(metadata pubsub.Metadata) ([]byte, error) {
|
||||
b, err := json.Marshal(metadata.Properties)
|
||||
|
||||
return b, err
|
||||
}
|
||||
|
||||
//Publish the topic to GCP Pubsub
|
||||
// Publish the topic to GCP Pubsub
|
||||
func (g *GCPPubSub) Publish(req *pubsub.PublishRequest) error {
|
||||
if !g.metadata.DisableEntityManagement {
|
||||
err := g.ensureTopic(req.Topic)
|
||||
|
@ -116,6 +118,7 @@ func (g *GCPPubSub) handleSubscriptionMessages(topic *gcppubsub.Topic, sub *gcpp
|
|||
m.Ack()
|
||||
}
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -125,6 +128,7 @@ func (g *GCPPubSub) ensureTopic(topic string) error {
|
|||
if !exists {
|
||||
_, err = g.client.CreateTopic(context.Background(), topic)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -144,9 +148,14 @@ func (g *GCPPubSub) ensureSubscription(subscription string, topic string) error
|
|||
_, subErr = g.client.CreateSubscription(context.Background(), g.metadata.ConsumerID,
|
||||
gcppubsub.SubscriptionConfig{Topic: g.getTopic(topic)})
|
||||
}
|
||||
|
||||
return subErr
|
||||
}
|
||||
|
||||
func (g *GCPPubSub) getSubscription(subscription string) *gcppubsub.Subscription {
|
||||
return g.client.Subscription(subscription)
|
||||
}
|
||||
|
||||
func (g *GCPPubSub) Close() error {
|
||||
return g.client.Close()
|
||||
}
|
||||
|
|
|
@ -4,16 +4,17 @@ import (
|
|||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/dapr/components-contrib/pubsub"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
m := pubsub.Metadata{}
|
||||
m.Properties = map[string]string{"auth_provider_x509_cert_url": "https://auth", "auth_uri": "https://auth", "client_x509_cert_url": "https://cert", "client_email": "test@test.com", "client_id": "id", "private_key": "****",
|
||||
"private_key_id": "key_id", "project_id": "project1", "token_uri": "https://token", "type": "serviceaccount"}
|
||||
m.Properties = map[string]string{
|
||||
"auth_provider_x509_cert_url": "https://auth", "auth_uri": "https://auth", "client_x509_cert_url": "https://cert", "client_email": "test@test.com", "client_id": "id", "private_key": "****",
|
||||
"private_key_id": "key_id", "project_id": "project1", "token_uri": "https://token", "type": "serviceaccount",
|
||||
}
|
||||
ps := GCPPubSub{logger: logger.NewLogger("test")}
|
||||
b, err := ps.parseMetadata(m)
|
||||
assert.Nil(t, err)
|
||||
|
|
|
@ -33,6 +33,7 @@ func parseHazelcastMetadata(meta pubsub.Metadata) (metadata, error) {
|
|||
} else {
|
||||
return m, errors.New("hazelcast error: missing hazelcast servers")
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
|
@ -82,6 +83,12 @@ func (p *Hazelcast) Subscribe(req pubsub.SubscribeRequest, handler pubsub.Handle
|
|||
return nil
|
||||
}
|
||||
|
||||
func (p *Hazelcast) Close() error {
|
||||
p.client.Shutdown()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type hazelcastMessageListener struct {
|
||||
topicName string
|
||||
pubsubHandler pubsub.Handler
|
||||
|
@ -92,6 +99,7 @@ func (l *hazelcastMessageListener) OnMessage(message hazelcastCore.Message) erro
|
|||
if !ok {
|
||||
return errors.New("hazelcast error: cannot cast message to byte array")
|
||||
}
|
||||
|
||||
return l.handleMessageObject(msg)
|
||||
}
|
||||
|
||||
|
|
|
@ -114,6 +114,7 @@ func (k *Kafka) Init(metadata pubsub.Metadata) error {
|
|||
k.topics = make(map[string]bool)
|
||||
|
||||
k.logger.Debug("Kafka message bus initialization complete")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -154,7 +155,6 @@ func (k *Kafka) closeSubscripionResources() {
|
|||
if k.cg != nil {
|
||||
k.cancel()
|
||||
err := k.cg.Close()
|
||||
|
||||
if err != nil {
|
||||
k.logger.Errorf("Error closing consumer group: %v", err)
|
||||
}
|
||||
|
@ -175,7 +175,6 @@ func (k *Kafka) Subscribe(req pubsub.SubscribeRequest, handler pubsub.Handler) e
|
|||
k.closeSubscripionResources()
|
||||
|
||||
cg, err := sarama.NewConsumerGroup(k.brokers, k.consumerGroup, k.config)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -195,7 +194,6 @@ func (k *Kafka) Subscribe(req pubsub.SubscribeRequest, handler pubsub.Handler) e
|
|||
defer func() {
|
||||
k.logger.Debugf("Closing ConsumerGroup for topics: %v", topics)
|
||||
err := k.cg.Close()
|
||||
|
||||
if err != nil {
|
||||
k.logger.Errorf("Error closing consumer group: %v", err)
|
||||
}
|
||||
|
@ -219,6 +217,7 @@ func (k *Kafka) Subscribe(req pubsub.SubscribeRequest, handler pubsub.Handler) e
|
|||
}()
|
||||
|
||||
<-ready
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -245,13 +244,12 @@ func (k *Kafka) getKafkaMetadata(metadata pubsub.Metadata) (*kafkaMetadata, erro
|
|||
return nil, errors.New("kafka error: 'authRequired' attribute was empty")
|
||||
}
|
||||
validAuthRequired, err := strconv.ParseBool(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.New("kafka error: invalid value for 'authRequired' attribute")
|
||||
}
|
||||
meta.AuthRequired = validAuthRequired
|
||||
|
||||
//ignore SASL properties if authRequired is false
|
||||
// ignore SASL properties if authRequired is false
|
||||
if meta.AuthRequired {
|
||||
if val, ok := metadata.Properties["saslUsername"]; ok && val != "" {
|
||||
meta.SaslUsername = val
|
||||
|
@ -283,6 +281,7 @@ func (k *Kafka) getSyncProducer(meta *kafkaMetadata) (sarama.SyncProducer, error
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return producer, nil
|
||||
}
|
||||
|
||||
|
@ -293,8 +292,15 @@ func updateAuthInfo(config *sarama.Config, saslUsername, saslPassword string) {
|
|||
config.Net.SASL.Mechanism = sarama.SASLTypePlaintext
|
||||
|
||||
config.Net.TLS.Enable = true
|
||||
// nolint: gosec
|
||||
config.Net.TLS.Config = &tls.Config{
|
||||
//InsecureSkipVerify: true,
|
||||
// InsecureSkipVerify: true,
|
||||
ClientAuth: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func (k *Kafka) Close() error {
|
||||
k.closeSubscripionResources()
|
||||
|
||||
return k.producer.Close()
|
||||
}
|
||||
|
|
|
@ -8,9 +8,8 @@ package kafka
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
|
||||
"github.com/dapr/components-contrib/pubsub"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
|
|
@ -15,11 +15,10 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/dapr/components-contrib/pubsub"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
mqtt "github.com/eclipse/paho.mqtt.golang"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -45,9 +44,12 @@ const (
|
|||
|
||||
// mqttPubSub type allows sending and receiving data to/from MQTT broker.
|
||||
type mqttPubSub struct {
|
||||
client mqtt.Client
|
||||
producer mqtt.Client
|
||||
consumer mqtt.Client
|
||||
metadata *metadata
|
||||
logger logger.Logger
|
||||
topics map[string]byte
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
// NewMQTTPubSub returns a new mqttPubSub instance.
|
||||
|
@ -58,6 +60,7 @@ func NewMQTTPubSub(logger logger.Logger) pubsub.PubSub {
|
|||
// isValidPEM validates the provided input has PEM formatted block.
|
||||
func isValidPEM(val string) bool {
|
||||
block, _ := pem.Decode([]byte(val))
|
||||
|
||||
return block != nil
|
||||
}
|
||||
|
||||
|
@ -134,18 +137,18 @@ func (m *mqttPubSub) Init(metadata pubsub.Metadata) error {
|
|||
}
|
||||
m.metadata = mqttMeta
|
||||
|
||||
uri, err := url.Parse(m.metadata.url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, err := m.connect(uri)
|
||||
// mqtt broker allows only one connection at a given time from a clientID.
|
||||
producerClientID := fmt.Sprintf("%s-producer", m.metadata.clientID)
|
||||
p, err := m.connect(producerClientID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.client = client
|
||||
m.producer = p
|
||||
m.topics = make(map[string]byte)
|
||||
|
||||
m.logger.Debug("mqtt message bus initialization complete")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -153,29 +156,60 @@ func (m *mqttPubSub) Init(metadata pubsub.Metadata) error {
|
|||
func (m *mqttPubSub) Publish(req *pubsub.PublishRequest) error {
|
||||
m.logger.Debugf("mqtt publishing topic %s with data: %v", req.Topic, req.Data)
|
||||
|
||||
token := m.client.Publish(req.Topic, m.metadata.qos, m.metadata.retain, req.Data)
|
||||
token := m.producer.Publish(req.Topic, m.metadata.qos, m.metadata.retain, req.Data)
|
||||
if !token.WaitTimeout(defaultWait) || token.Error() != nil {
|
||||
return fmt.Errorf("mqtt error from publish: %v", token.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Subscribe to the mqtt pub sub topic.
|
||||
func (m *mqttPubSub) Subscribe(req pubsub.SubscribeRequest, handler pubsub.Handler) error {
|
||||
token := m.client.Subscribe(
|
||||
req.Topic,
|
||||
m.metadata.qos,
|
||||
func(client mqtt.Client, mqttMsg mqtt.Message) {
|
||||
handler(context.Background(), &pubsub.NewMessage{Topic: req.Topic, Data: mqttMsg.Payload()})
|
||||
})
|
||||
if err := token.Error(); err != nil {
|
||||
return fmt.Errorf("mqtt error from subscribe: %v", err)
|
||||
m.topics[req.Topic] = m.metadata.qos
|
||||
|
||||
// reset synchronization
|
||||
if m.consumer != nil {
|
||||
m.logger.Warnf("re-initializing the subscriber")
|
||||
m.cancel()
|
||||
m.consumer.Disconnect(0)
|
||||
}
|
||||
|
||||
// mqtt broker allows only one connection at a given time from a clientID.
|
||||
consumerClientID := fmt.Sprintf("%s-consumer", m.metadata.clientID)
|
||||
c, err := m.connect(consumerClientID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.consumer = c
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
m.cancel = cancel
|
||||
|
||||
go func() {
|
||||
token := m.consumer.SubscribeMultiple(
|
||||
m.topics,
|
||||
func(client mqtt.Client, mqttMsg mqtt.Message) {
|
||||
handler(&pubsub.NewMessage{Topic: req.Topic, Data: mqttMsg.Payload()})
|
||||
})
|
||||
if err := token.Error(); err != nil {
|
||||
m.logger.Errorf("mqtt error from subscribe: %v", err)
|
||||
}
|
||||
|
||||
if ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mqttPubSub) connect(uri *url.URL) (mqtt.Client, error) {
|
||||
opts := m.createClientOptions(uri)
|
||||
func (m *mqttPubSub) connect(clientID string) (mqtt.Client, error) {
|
||||
uri, err := url.Parse(m.metadata.url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts := m.createClientOptions(uri, clientID)
|
||||
client := mqtt.NewClient(opts)
|
||||
token := client.Connect()
|
||||
for !token.WaitTimeout(defaultWait) {
|
||||
|
@ -183,16 +217,18 @@ func (m *mqttPubSub) connect(uri *url.URL) (mqtt.Client, error) {
|
|||
if err := token.Error(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (m *mqttPubSub) NewTLSConfig() *tls.Config {
|
||||
func (m *mqttPubSub) newTLSConfig() *tls.Config {
|
||||
tlsConfig := new(tls.Config)
|
||||
|
||||
if m.metadata.clientCert != "" && m.metadata.clientKey != "" {
|
||||
cert, err := tls.X509KeyPair([]byte(m.metadata.clientCert), []byte(m.metadata.clientKey))
|
||||
if err != nil {
|
||||
m.logger.Warnf("unable to load client certificate and key pair. Err: %v", err)
|
||||
|
||||
return tlsConfig
|
||||
}
|
||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
||||
|
@ -208,15 +244,23 @@ func (m *mqttPubSub) NewTLSConfig() *tls.Config {
|
|||
return tlsConfig
|
||||
}
|
||||
|
||||
func (m *mqttPubSub) createClientOptions(uri *url.URL) *mqtt.ClientOptions {
|
||||
func (m *mqttPubSub) createClientOptions(uri *url.URL, clientID string) *mqtt.ClientOptions {
|
||||
opts := mqtt.NewClientOptions()
|
||||
opts.SetClientID(m.metadata.clientID)
|
||||
opts.SetClientID(clientID)
|
||||
opts.SetCleanSession(m.metadata.cleanSession)
|
||||
opts.AddBroker(uri.Scheme + "://" + uri.Host)
|
||||
opts.SetUsername(uri.User.Username())
|
||||
password, _ := uri.User.Password()
|
||||
opts.SetPassword(password)
|
||||
// tls config
|
||||
opts.SetTLSConfig(m.NewTLSConfig())
|
||||
opts.SetTLSConfig(m.newTLSConfig())
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
func (m *mqttPubSub) Close() error {
|
||||
m.consumer.Disconnect(0)
|
||||
m.producer.Disconnect(0)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ func (n *natsPubSub) Init(metadata pubsub.Metadata) error {
|
|||
n.logger.Debugf("connected to nats at %s", m.natsURL)
|
||||
|
||||
n.natsConn = natsConn
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -71,6 +72,7 @@ func (n *natsPubSub) Publish(req *pubsub.PublishRequest) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("nats: error from publish: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -85,3 +87,9 @@ func (n *natsPubSub) Subscribe(req pubsub.SubscribeRequest, handler pubsub.Handl
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *natsPubSub) Close() error {
|
||||
n.natsConn.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -9,9 +9,8 @@ import (
|
|||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/dapr/components-contrib/pubsub"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParseNATSMetadata(t *testing.T) {
|
||||
|
|
|
@ -17,7 +17,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/dapr/components-contrib/pubsub"
|
||||
"github.com/nats-io/gnatsd/logger"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
nats "github.com/nats-io/nats.go"
|
||||
stan "github.com/nats-io/stan.go"
|
||||
"github.com/nats-io/stan.go/pb"
|
||||
|
@ -51,7 +51,7 @@ const (
|
|||
)
|
||||
|
||||
const (
|
||||
consumerID = "consumerID" //passed in by Dapr runtime
|
||||
consumerID = "consumerID" // passed in by Dapr runtime
|
||||
subscriptionType = "subscriptionType"
|
||||
)
|
||||
|
||||
|
@ -165,7 +165,10 @@ func (n *natsStreamingPubSub) Init(metadata pubsub.Metadata) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("nats-streaming: error connecting to nats streaming server %s: %s", m.natsStreamingClusterID, err)
|
||||
}
|
||||
n.logger.Debugf("connected to natsstreaming at %s", m.natsURL)
|
||||
|
||||
n.natStreamingConn = natStreamingConn
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -174,6 +177,7 @@ func (n *natsStreamingPubSub) Publish(req *pubsub.PublishRequest) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("nats-streaming: error from publish: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -200,6 +204,11 @@ func (n *natsStreamingPubSub) Subscribe(req pubsub.SubscribeRequest, handler pub
|
|||
if err != nil {
|
||||
return fmt.Errorf("nats-streaming: subscribe error %s", err)
|
||||
}
|
||||
if n.metadata.subscriptionType == subscriptionTypeTopic {
|
||||
n.logger.Debugf("nats: subscribed to subject %s", req.Topic)
|
||||
} else if n.metadata.subscriptionType == subscriptionTypeQueueGroup {
|
||||
n.logger.Debugf("nats: subscribed to subject %s with queue group %s", req.Topic, n.metadata.natsQueueGroupName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -214,13 +223,13 @@ func (n *natsStreamingPubSub) subscriptionOptions() ([]stan.SubscriptionOption,
|
|||
switch {
|
||||
case n.metadata.deliverNew == deliverNewTrue:
|
||||
options = append(options, stan.StartAt(pb.StartPosition_NewOnly))
|
||||
case n.metadata.startAtSequence >= 1: //messages index start from 1, this is a valid check
|
||||
case n.metadata.startAtSequence >= 1: // messages index start from 1, this is a valid check
|
||||
options = append(options, stan.StartAtSequence(n.metadata.startAtSequence))
|
||||
case n.metadata.startWithLastReceived == startWithLastReceivedTrue:
|
||||
options = append(options, stan.StartWithLastReceived())
|
||||
case n.metadata.deliverAll == deliverAllTrue:
|
||||
options = append(options, stan.DeliverAllAvailable())
|
||||
case n.metadata.startAtTimeDelta > (1 * time.Nanosecond): //as long as its a valid time.Duration
|
||||
case n.metadata.startAtTimeDelta > (1 * time.Nanosecond): // as long as its a valid time.Duration
|
||||
options = append(options, stan.StartAtTimeDelta(n.metadata.startAtTimeDelta))
|
||||
case n.metadata.startAtTime != "":
|
||||
if n.metadata.startAtTimeFormat != "" {
|
||||
|
@ -251,3 +260,7 @@ func genRandomString(n int) string {
|
|||
|
||||
return clientID
|
||||
}
|
||||
|
||||
func (n *natsStreamingPubSub) Close() error {
|
||||
return n.natStreamingConn.Close()
|
||||
}
|
||||
|
|
|
@ -10,9 +10,8 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/dapr/components-contrib/pubsub"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParseNATSStreamingForMetadataMandatoryOptionsMissing(t *testing.T) {
|
||||
|
@ -127,50 +126,65 @@ func TestParseNATSStreamingMetadataForValidSubscriptionOptions(t *testing.T) {
|
|||
|
||||
tests := []test{
|
||||
|
||||
{"using startWithLastReceived", map[string]string{
|
||||
natsURL: "nats://foo.bar:4222",
|
||||
natsStreamingClusterID: "testcluster",
|
||||
consumerID: "consumer1",
|
||||
subscriptionType: "topic",
|
||||
startWithLastReceived: "true",
|
||||
{
|
||||
"using startWithLastReceived",
|
||||
map[string]string{
|
||||
natsURL: "nats://foo.bar:4222",
|
||||
natsStreamingClusterID: "testcluster",
|
||||
consumerID: "consumer1",
|
||||
subscriptionType: "topic",
|
||||
startWithLastReceived: "true",
|
||||
},
|
||||
"startWithLastReceived", "true",
|
||||
},
|
||||
"startWithLastReceived", "true"},
|
||||
|
||||
{"using deliverAll", map[string]string{
|
||||
natsURL: "nats://foo.bar:4222",
|
||||
natsStreamingClusterID: "testcluster",
|
||||
consumerID: "consumer1",
|
||||
subscriptionType: "topic",
|
||||
deliverAll: "true",
|
||||
{
|
||||
"using deliverAll",
|
||||
map[string]string{
|
||||
natsURL: "nats://foo.bar:4222",
|
||||
natsStreamingClusterID: "testcluster",
|
||||
consumerID: "consumer1",
|
||||
subscriptionType: "topic",
|
||||
deliverAll: "true",
|
||||
},
|
||||
"deliverAll", "true",
|
||||
},
|
||||
"deliverAll", "true"},
|
||||
|
||||
{"using deliverNew", map[string]string{
|
||||
natsURL: "nats://foo.bar:4222",
|
||||
natsStreamingClusterID: "testcluster",
|
||||
consumerID: "consumer1",
|
||||
subscriptionType: "topic",
|
||||
deliverNew: "true",
|
||||
{
|
||||
"using deliverNew",
|
||||
map[string]string{
|
||||
natsURL: "nats://foo.bar:4222",
|
||||
natsStreamingClusterID: "testcluster",
|
||||
consumerID: "consumer1",
|
||||
subscriptionType: "topic",
|
||||
deliverNew: "true",
|
||||
},
|
||||
"deliverNew", "true",
|
||||
},
|
||||
"deliverNew", "true"},
|
||||
|
||||
{"using startAtSequence", map[string]string{
|
||||
natsURL: "nats://foo.bar:4222",
|
||||
natsStreamingClusterID: "testcluster",
|
||||
consumerID: "consumer1",
|
||||
subscriptionType: "topic",
|
||||
startAtSequence: "42",
|
||||
{
|
||||
"using startAtSequence",
|
||||
map[string]string{
|
||||
natsURL: "nats://foo.bar:4222",
|
||||
natsStreamingClusterID: "testcluster",
|
||||
consumerID: "consumer1",
|
||||
subscriptionType: "topic",
|
||||
startAtSequence: "42",
|
||||
},
|
||||
"startAtSequence", "42",
|
||||
},
|
||||
"startAtSequence", "42"},
|
||||
|
||||
{"using startAtTimeDelta", map[string]string{
|
||||
natsURL: "nats://foo.bar:4222",
|
||||
natsStreamingClusterID: "testcluster",
|
||||
consumerID: "consumer1",
|
||||
subscriptionType: "topic",
|
||||
startAtTimeDelta: "1h",
|
||||
{
|
||||
"using startAtTimeDelta",
|
||||
map[string]string{
|
||||
natsURL: "nats://foo.bar:4222",
|
||||
natsStreamingClusterID: "testcluster",
|
||||
consumerID: "consumer1",
|
||||
subscriptionType: "topic",
|
||||
startAtTimeDelta: "1h",
|
||||
},
|
||||
"startAtTimeDelta", "1h",
|
||||
},
|
||||
"startAtTimeDelta", "1h"},
|
||||
}
|
||||
|
||||
for _, _test := range tests {
|
||||
|
@ -196,6 +210,7 @@ func TestParseNATSStreamingMetadataForValidSubscriptionOptions(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseNATSStreamingMetadata(t *testing.T) {
|
||||
t.Run("mandatory metadata provided", func(t *testing.T) {
|
||||
fakeProperties := map[string]string{
|
||||
|
@ -262,9 +277,9 @@ func TestParseNATSStreamingMetadata(t *testing.T) {
|
|||
assert.NotEmpty(t, m.subscriptionType)
|
||||
assert.NotEmpty(t, m.natsQueueGroupName)
|
||||
assert.NotEmpty(t, m.startAtSequence)
|
||||
//startWithLastReceived ignored
|
||||
// startWithLastReceived ignored
|
||||
assert.Empty(t, m.startWithLastReceived)
|
||||
//deliverAll will be ignored
|
||||
// deliverAll will be ignored
|
||||
assert.Empty(t, m.deliverAll)
|
||||
|
||||
assert.Equal(t, fakeProperties[natsURL], m.natsURL)
|
||||
|
@ -330,7 +345,7 @@ func TestSubscriptionOptionsForInvalidOptions(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSubscriptionOptions(t *testing.T) {
|
||||
//general
|
||||
// general
|
||||
t.Run("manual ACK option is present by default", func(t *testing.T) {
|
||||
natsStreaming := natsStreamingPubSub{metadata: metadata{}}
|
||||
opts, err := natsStreaming.subscriptionOptions()
|
||||
|
|
|
@ -11,7 +11,8 @@ import "context"
|
|||
type PubSub interface {
|
||||
Init(metadata Metadata) error
|
||||
Publish(req *PublishRequest) error
|
||||
Subscribe(req SubscribeRequest, handler Handler) error
|
||||
Subscribe(req SubscribeRequest, handler pubsub.Handler) error
|
||||
Close() error
|
||||
}
|
||||
|
||||
// Handler is the handler used to invoke the app handler
|
||||
|
|
|
@ -8,9 +8,8 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/apache/pulsar-client-go/pulsar"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
|
||||
"github.com/dapr/components-contrib/pubsub"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -66,6 +65,7 @@ func (p *Pulsar) Init(metadata pubsub.Metadata) error {
|
|||
|
||||
p.client = client
|
||||
p.metadata = *m
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -126,3 +126,9 @@ func (p *Pulsar) HandleMessage(m pulsar.ConsumerMessage, topic string, handler p
|
|||
m.Ack(m.Message)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Pulsar) Close() error {
|
||||
p.client.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -3,9 +3,8 @@ package pulsar
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/dapr/components-contrib/pubsub"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParsePulsarMetadata(t *testing.T) {
|
||||
|
|
|
@ -17,7 +17,7 @@ func getFakeProperties() map[string]string {
|
|||
}
|
||||
|
||||
func TestCreateMetadata(t *testing.T) {
|
||||
var booleanFlagTests = []struct {
|
||||
booleanFlagTests := []struct {
|
||||
in string
|
||||
expected bool
|
||||
}{
|
||||
|
@ -82,7 +82,7 @@ func TestCreateMetadata(t *testing.T) {
|
|||
assert.Empty(t, m.consumerID)
|
||||
})
|
||||
|
||||
var invalidDeliveryModes = []string{"3", "10", "-1"}
|
||||
invalidDeliveryModes := []string{"3", "10", "-1"}
|
||||
|
||||
for _, deliveryMode := range invalidDeliveryModes {
|
||||
t.Run(fmt.Sprintf("deliveryMode value=%s", deliveryMode), func(t *testing.T) {
|
||||
|
|
|
@ -58,6 +58,7 @@ func (r *rabbitMQ) Init(metadata pubsub.Metadata) error {
|
|||
|
||||
r.connection = conn
|
||||
r.channel = ch
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -111,7 +112,6 @@ func (r *rabbitMQ) Subscribe(req pubsub.SubscribeRequest, handler pubsub.Handler
|
|||
false, // noWait
|
||||
nil,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -170,3 +170,7 @@ func (r *rabbitMQ) ensureExchangeDeclared(exchange string) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *rabbitMQ) Close() error {
|
||||
return r.connection.Close()
|
||||
}
|
||||
|
|
|
@ -13,9 +13,8 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
|
||||
"github.com/dapr/components-contrib/pubsub"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
"github.com/go-redis/redis/v7"
|
||||
)
|
||||
|
||||
|
@ -97,6 +96,7 @@ func (r *redisStreams) Init(metadata pubsub.Metadata) error {
|
|||
}
|
||||
|
||||
r.client = client
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -118,6 +118,7 @@ func (r *redisStreams) Subscribe(req pubsub.SubscribeRequest, handler pubsub.Han
|
|||
r.logger.Warnf("redis streams: %s", err)
|
||||
}
|
||||
go r.beginReadingFromStream(req.Topic, r.metadata.consumerID, handler)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -164,11 +165,16 @@ func (r *redisStreams) beginReadingFromStream(stream, consumerID string, handler
|
|||
streams, err := r.readFromStream(stream, consumerID, start)
|
||||
if err != nil {
|
||||
r.logger.Errorf("redis streams: error reading from stream %s: %s", stream, err)
|
||||
|
||||
return
|
||||
}
|
||||
r.processStreams(consumerID, streams, handler)
|
||||
|
||||
//continue with new non received items
|
||||
// continue with new non received items
|
||||
start = ">"
|
||||
}
|
||||
}
|
||||
|
||||
func (r *redisStreams) Close() error {
|
||||
return r.client.Close()
|
||||
}
|
||||
|
|
|
@ -12,11 +12,10 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis/v7"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/dapr/components-contrib/pubsub"
|
||||
"github.com/dapr/dapr/pkg/logger"
|
||||
"github.com/go-redis/redis/v7"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func getFakeProperties() map[string]string {
|
||||
|
@ -137,5 +136,6 @@ func generateRedisStreamTestData(topicCount, messageCount int, data string) []re
|
|||
Messages: xmessageArray,
|
||||
}
|
||||
}
|
||||
|
||||
return redisStreams
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue