Merge branch 'master' into merge-1.9

Signed-off-by: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>
This commit is contained in:
ItalyPaleAle 2022-10-11 20:26:35 +00:00
commit 3bc20a1de5
130 changed files with 3158 additions and 4610 deletions

View File

@ -31,6 +31,15 @@ jobs:
generate-matrix:
runs-on: ubuntu-latest
steps:
- name: Parse repository_dispatch payload
if: github.event_name == 'repository_dispatch'
working-directory: ${{ github.workspace }}
run: |
if [ ${{ github.event.client_payload.command }} = "ok-to-test" ]; then
echo "CHECKOUT_REF=${{ github.event.client_payload.pull_head_ref }}" >> $GITHUB_ENV
echo "PR_NUMBER=${{ github.event.client_payload.issue.number }}" >> $GITHUB_ENV
fi
- name: Install yq
run: |
sudo snap install yq
@ -113,6 +122,21 @@ jobs:
EOF
)
echo "::set-output name=cloud-components::$CRON_COMPONENTS"
- name: Create PR comment
if: env.PR_NUMBER != ''
uses: artursouza/sticky-pull-request-comment@v2.2.0
with:
header: ${{ github.run_id }}
number: ${{ env.PR_NUMBER }}
GITHUB_TOKEN: ${{ secrets.DAPR_BOT_TOKEN }}
message: |
# Components certification test
🔗 **[Link to Action run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})**
Commit ref: ${{ env.CHECKOUT_REF }}
outputs:
pr-components: ${{ steps.pr-components.outputs.pr-components }}
cloud-components: ${{ steps.cloud-components.outputs.cloud-components }}
@ -124,8 +148,6 @@ jobs:
run:
shell: bash
needs: generate-matrix
env:
PROJECT_PATH: ./src/github.com/dapr/components-contrib
strategy:
fail-fast: false # Keep running even if one component fails
@ -147,10 +169,9 @@ jobs:
echo "CHECKOUT_REF=${{ github.event.client_payload.pull_head_ref }}" >> $GITHUB_ENV
fi
- name: Check out code onto GOPATH
- name: Check out code
uses: actions/checkout@v2
with:
path: ${{ env.PROJECT_PATH }}
repository: ${{ env.CHECKOUT_REPO }}
ref: ${{ env.CHECKOUT_REF }}
@ -162,10 +183,13 @@ jobs:
- name: Configure certification test and source path
run: |
TEST_COMPONENT=$(echo ${{ matrix.component }} | sed -E 's/\./\//g')
export TEST_PATH="${PROJECT_PATH}/tests/certification/${TEST_COMPONENT}"
export TEST_PATH="tests/certification/${TEST_COMPONENT}"
echo "TEST_PATH=$TEST_PATH" >> $GITHUB_ENV
export SOURCE_PATH="github.com/dapr/components-contrib/${TEST_COMPONENT}"
echo "SOURCE_PATH=$SOURCE_PATH" >> $GITHUB_ENV
# converts slashes to dots in this string, so that it doesn't consider them sub-folders
export SOURCE_PATH_LINEAR=$(echo "$SOURCE_PATH" |sed 's#/#\.#g')
echo "SOURCE_PATH_LINEAR=$SOURCE_PATH_LINEAR" >> $GITHUB_ENV
- uses: Azure/login@v1
with:
@ -220,7 +244,6 @@ jobs:
working-directory: ${{ env.TEST_PATH }}
run: |
echo "Running certification tests for ${{ matrix.component }} ... "
export GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn
set +e
gotestsum --jsonfile ${{ env.TEST_OUTPUT_FILE_PREFIX }}_certification.json \
@ -254,15 +277,36 @@ jobs:
done
if [[ -v CERTIFICATION_FAILURE ]]; then
echo "CERTIFICATION_FAILURE=true" >> $GITHUB_ENV
exit 1
else
echo "CERTIFICATION_FAILURE=false" >> $GITHUB_ENV
fi
- name: Prepare test result info
if: always()
run: |
mkdir -p tmp/result_files
echo "Writing to tmp/result_files/${{ matrix.component }}.txt"
if [[ "${{ env.CERTIFICATION_FAILURE }}" == "true" ]]; then
echo "0" >> "tmp/result_files/${{ matrix.component }}.txt"
else
echo "1" >> "tmp/result_files/${{ matrix.component }}.txt"
fi
- name: Upload result files
uses: actions/upload-artifact@v3
if: always()
with:
name: result_files
path: tmp/result_files
retention-days: 1
- name: Prepare Cert Coverage Info
if: github.event_name == 'schedule'
run: |
mkdir -p tmp/cov_files
SOURCE_PATH_LINEAR=$(echo ${{ env.SOURCE_PATH }} |sed 's#/#\.#g') # converts slashes to dots in this string, so that it doesn't consider them sub-folders
echo "${{ env.COVERAGE_LINE }}" >> tmp/cov_files/$SOURCE_PATH_LINEAR.txt
echo "${{ env.COVERAGE_LINE }}" >> tmp/cov_files/${{ env.SOURCE_PATH_LINEAR }}.txt
- name: Upload Cert Coverage Artifact
uses: actions/upload-artifact@v3
@ -290,22 +334,148 @@ jobs:
path: ${{ env.TEST_OUTPUT_FILE_PREFIX }}_certification.*
post_job:
name: Notify Total coverage
name: Post-completion
runs-on: ubuntu-latest
needs: certification
if: github.event_name == 'schedule'
if: always()
needs:
- certification
- generate-matrix
steps:
- name: Parse repository_dispatch payload
if: github.event_name == 'repository_dispatch'
working-directory: ${{ github.workspace }}
run: |
if [ ${{ github.event.client_payload.command }} = "ok-to-test" ]; then
echo "CHECKOUT_REF=${{ github.event.client_payload.pull_head_ref }}" >> $GITHUB_ENV
echo "PR_NUMBER=${{ github.event.client_payload.issue.number }}" >> $GITHUB_ENV
fi
- name: Download test result artifact
if: always() && env.PR_NUMBER != ''
uses: actions/download-artifact@v3
continue-on-error: true
id: testresults
with:
name: result_files
path: tmp/result_files
- name: Build message
if: always() && env.PR_NUMBER != ''
# Abusing of the github-script action to be able to write this in JS
uses: actions/github-script@v6
with:
script: |
const prComponents = ('${{ needs.generate-matrix.outputs.pr-components }}' && JSON.parse('${{ needs.generate-matrix.outputs.pr-components }}')) || []
const cloudComponents = ('${{ needs.generate-matrix.outputs.cloud-components }}' && JSON.parse('${{ needs.generate-matrix.outputs.cloud-components }}')) || []
const allComponents = [...prComponents, ...cloudComponents]
const basePath = '${{ steps.testresults.outputs.download-path }}'
const testType = 'certification'
const fs = require('fs')
const path = require('path')
let message = `# Components ${testType} test
🔗 **[Link to Action run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})**
Commit ref: ${{ env.CHECKOUT_REF }}`
let allSuccess = true
let allFound = true
let notSuccess = []
let notFound = []
for (let i = 0; i < allComponents.length; i++) {
let component = allComponents[i]
if (!component) {
continue
}
if (typeof component == 'object') {
component = component.component
}
let found = false
let success = false
try {
let read =fs.readFileSync(path.join(basePath, component + '.txt'), 'utf8')
read = read.split('\n')[0]
switch (read) {
case '1':
found = true
success = true
break
case '0':
found = true
success = false
}
} catch (e) {
// ignore errors, leave found = false
}
if (!found) {
allFound = false
notFound.push(component)
}
if (!success) {
allSuccess = false
notSuccess.push(component)
}
}
if (allSuccess) {
if (allFound) {
message += '\n\n' + `# ✅ All ${testType} tests passed
All tests have reported a successful status` + '\n\n'
} else {
message += '\n\n' + `# ⚠️ Some ${testType} tests did not report status
Although there were no failures reported, some tests did not report a status:` + '\n\n'
for (let i = 0; i < notFound.length; i++) {
message += '- ' + notFound[i] + '\n'
}
message += '\n'
}
} else {
message += '\n\n' + `# ❌ Some ${testType} tests failed
These tests failed:` + '\n\n'
for (let i = 0; i < notSuccess.length; i++) {
message += '- ' + notSuccess[i] + '\n'
}
message += '\n'
if (!allFound) {
message += 'Additionally, some tests did not report a status:\n\n'
for (let i = 0; i < notFound.length; i++) {
message += '- ' + notFound[i] + '\n'
}
message += '\n'
}
}
fs.writeFileSync('message.txt', message)
- name: Replace PR comment
if: always() && env.PR_NUMBER != ''
uses: artursouza/sticky-pull-request-comment@v2.2.0
with:
header: ${{ github.run_id }}
number: ${{ env.PR_NUMBER }}
GITHUB_TOKEN: ${{ secrets.DAPR_BOT_TOKEN }}
path: message.txt
- name: Download Cert Coverage Artifact
uses: actions/download-artifact@v3
continue-on-error: true
if: success() && github.event_name == 'schedule'
id: download
with:
name: certtest_cov
path: tmp/cov_files
- name: Calculate total coverage
if: success() && github.event_name == 'schedule'
run: |
threshold=80.0
threshold=60.0
echo "threshold=$threshold" >> $GITHUB_ENV
aboveThreshold=0
totalFiles=0
@ -325,14 +495,15 @@ jobs:
echo "totalPer=$totalPer" >> $GITHUB_ENV
echo "aboveThreshold=$aboveThreshold" >> $GITHUB_ENV
echo "totalFiles=$totalFiles" >> $GITHUB_ENV
done < ${{steps.download.outputs.download-path}}/$f
done < "${{steps.download.outputs.download-path}}/$f"
done
continue-on-error: true
- name: Final Coverage Discord Notification
if: success() && github.event_name == 'schedule'
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_MONITORING_WEBHOOK_URL }}
uses: Ilshidur/action-discord@0c4b27844ba47cb1c7bee539c8eead5284ce9fa9
continue-on-error: true
with:
args: 'Total Coverage for Certification Tests is {{ totalPer }}%. {{ aboveThreshold }} out of {{ totalFiles }} components have certification tests with code coverage > {{ threshold }}%'
args: 'Total Coverage for Certification Tests is {{ totalPer }}%. {{ aboveThreshold }} out of {{ totalFiles }} components have certification tests with code coverage > {{ threshold }}%'

View File

@ -22,7 +22,7 @@ on:
pull_request:
branches:
- master
- release-*
- 'release-*'
jobs:
# Based on whether this is a PR or a scheduled run, we will run a different
@ -31,6 +31,15 @@ jobs:
generate-matrix:
runs-on: ubuntu-latest
steps:
- name: Parse repository_dispatch payload
if: github.event_name == 'repository_dispatch'
working-directory: ${{ github.workspace }}
run: |
if [ ${{ github.event.client_payload.command }} = "ok-to-test" ]; then
echo "CHECKOUT_REF=${{ github.event.client_payload.pull_head_ref }}" >> $GITHUB_ENV
echo "PR_NUMBER=${{ github.event.client_payload.issue.number }}" >> $GITHUB_ENV
fi
- name: Install yq
run: |
sudo snap install yq
@ -133,6 +142,21 @@ jobs:
EOF
)
echo "::set-output name=cron-components::$CRON_COMPONENTS"
- name: Create PR comment
if: env.PR_NUMBER != ''
uses: artursouza/sticky-pull-request-comment@v2.2.0
with:
header: ${{ github.run_id }}
number: ${{ env.PR_NUMBER }}
GITHUB_TOKEN: ${{ secrets.DAPR_BOT_TOKEN }}
message: |
# Components conformance test
🔗 **[Link to Action run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})**
Commit ref: ${{ env.CHECKOUT_REF }}
outputs:
pr-components: ${{ steps.pr-components.outputs.pr-components }}
cron-components: ${{ steps.cron-components.outputs.cron-components }}
@ -143,10 +167,7 @@ jobs:
defaults:
run:
shell: bash
working-directory: ${{ env.PROJECT_PATH }}
needs: generate-matrix
env:
PROJECT_PATH: ./src/github.com/dapr/components-contrib
strategy:
fail-fast: false # Keep running even if one component fails
@ -168,12 +189,12 @@ jobs:
if [ ${{ github.event.client_payload.command }} = "ok-to-test" ]; then
echo "CHECKOUT_REPO=${{ github.event.client_payload.pull_head_repo }}" >> $GITHUB_ENV
echo "CHECKOUT_REF=${{ github.event.client_payload.pull_head_ref }}" >> $GITHUB_ENV
echo "PR_NUMBER=${{ github.event.client_payload.issue.number }}" >> $GITHUB_ENV
fi
- name: Check out code onto GOPATH
uses: actions/checkout@v2
with:
path: ${{ env.PROJECT_PATH }}
repository: ${{ env.CHECKOUT_REPO }}
ref: ${{ env.CHECKOUT_REF }}
@ -423,6 +444,25 @@ jobs:
exit 1
fi
- name: Prepare test result info
if: always()
run: |
mkdir -p tmp/result_files
echo "Writing to tmp/result_files/${{ matrix.component }}.txt"
if [[ "${{ env.CONFORMANCE_FAILURE }}" == "true" ]]; then
echo "0" >> "tmp/result_files/${{ matrix.component }}.txt"
else
echo "1" >> "tmp/result_files/${{ matrix.component }}.txt"
fi
- name: Upload result files
uses: actions/upload-artifact@v3
if: always()
with:
name: result_files
path: tmp/result_files
retention-days: 1
# Upload logs for test analytics to consume
- name: Upload test results
if: always()
@ -430,3 +470,133 @@ jobs:
with:
name: ${{ matrix.component }}_conformance_test
path: ${{ env.TEST_OUTPUT_FILE_PREFIX }}_conformance.*
post_job:
name: Post-completion
runs-on: ubuntu-latest
if: always()
needs:
- conformance
- generate-matrix
steps:
- name: Parse repository_dispatch payload
if: github.event_name == 'repository_dispatch'
working-directory: ${{ github.workspace }}
run: |
if [ ${{ github.event.client_payload.command }} = "ok-to-test" ]; then
echo "CHECKOUT_REF=${{ github.event.client_payload.pull_head_ref }}" >> $GITHUB_ENV
echo "PR_NUMBER=${{ github.event.client_payload.issue.number }}" >> $GITHUB_ENV
fi
- name: Download test result artifact
if: always() && env.PR_NUMBER != ''
uses: actions/download-artifact@v3
continue-on-error: true
id: testresults
with:
name: result_files
path: tmp/result_files
- name: Build message
if: always() && env.PR_NUMBER != ''
# Abusing of the github-script action to be able to write this in JS
uses: actions/github-script@v6
with:
script: |
const prComponents = ('${{ needs.generate-matrix.outputs.pr-components }}' && JSON.parse('${{ needs.generate-matrix.outputs.pr-components }}')) || []
const cronComponents = ('${{ needs.generate-matrix.outputs.cron-components }}' && JSON.parse('${{ needs.generate-matrix.outputs.cron-components }}')) || []
const allComponents = [...prComponents, ...cronComponents]
const basePath = '${{ steps.testresults.outputs.download-path }}'
const testType = 'conformance'
const fs = require('fs')
const path = require('path')
let message = `# Components ${testType} test
🔗 **[Link to Action run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})**
Commit ref: ${{ env.CHECKOUT_REF }}`
let allSuccess = true
let allFound = true
let notSuccess = []
let notFound = []
for (let i = 0; i < allComponents.length; i++) {
let component = allComponents[i]
if (!component) {
continue
}
if (typeof component == 'object') {
component = component.component
}
let found = false
let success = false
try {
let read =fs.readFileSync(path.join(basePath, component + '.txt'), 'utf8')
read = read.split('\n')[0]
switch (read) {
case '1':
found = true
success = true
break
case '0':
found = true
success = false
}
} catch (e) {
// ignore errors, leave found = false
}
if (!found) {
allFound = false
notFound.push(component)
}
if (!success) {
allSuccess = false
notSuccess.push(component)
}
}
if (allSuccess) {
if (allFound) {
message += '\n\n' + `# ✅ All ${testType} tests passed
All tests have reported a successful status` + '\n\n'
} else {
message += '\n\n' + `# ⚠️ Some ${testType} tests did not report status
Although there were no failures reported, some tests did not report a status:` + '\n\n'
for (let i = 0; i < notFound.length; i++) {
message += '- ' + notFound[i] + '\n'
}
message += '\n'
}
} else {
message += '\n\n' + `# ❌ Some ${testType} tests failed
These tests failed:` + '\n\n'
for (let i = 0; i < notSuccess.length; i++) {
message += '- ' + notSuccess[i] + '\n'
}
message += '\n'
if (!allFound) {
message += 'Additionally, some tests did not report a status:\n\n'
for (let i = 0; i < notFound.length; i++) {
message += '- ' + notFound[i] + '\n'
}
message += '\n'
}
}
fs.writeFileSync('message.txt', message)
- name: Replace PR comment
if: env.PR_NUMBER != ''
uses: artursouza/sticky-pull-request-comment@v2.2.0
with:
header: ${{ github.run_id }}
number: ${{ env.PR_NUMBER }}
GITHUB_TOKEN: ${{ secrets.DAPR_BOT_TOKEN }}
path: message.txt

View File

@ -35,12 +35,12 @@ jobs:
uses: actions/checkout@v2
- name: "Run FOSSA Scan"
uses: fossas/fossa-action@v1.1.0 # Use a specific version if locking is preferred
uses: fossas/fossa-action@v1.3.1 # Use a specific version if locking is preferred
with:
api-key: ${{ env.FOSSA_API_KEY }}
- name: "Run FOSSA Test"
uses: fossas/fossa-action@v1.1.0 # Use a specific version if locking is preferred
uses: fossas/fossa-action@v1.3.1 # Use a specific version if locking is preferred
with:
api-key: ${{ env.FOSSA_API_KEY }}
run-tests: true

View File

@ -16,6 +16,7 @@ package servicebusqueues
import (
"context"
"errors"
"fmt"
"sync"
"time"
@ -230,6 +231,7 @@ func (a *AzureServiceBusQueues) Read(subscribeCtx context.Context, handler bindi
err = sub.ReceiveAndBlock(
a.getHandlerFunc(handler),
a.metadata.LockRenewalInSec,
false, // Bulk is not supported here.
func() {
// Reset the backoff when the subscription is successful and we have received the first message
bo.Reset()
@ -268,7 +270,12 @@ func (a *AzureServiceBusQueues) Read(subscribeCtx context.Context, handler bindi
}
func (a *AzureServiceBusQueues) getHandlerFunc(handler bindings.Handler) impl.HandlerFunc {
return func(ctx context.Context, msg *servicebus.ReceivedMessage) error {
return func(ctx context.Context, asbMsgs []*servicebus.ReceivedMessage) ([]impl.HandlerResponseItem, error) {
if len(asbMsgs) != 1 {
return nil, fmt.Errorf("expected 1 message, got %d", len(asbMsgs))
}
msg := asbMsgs[0]
metadata := make(map[string]string)
metadata[id] = msg.MessageID
if msg.CorrelationID != nil {
@ -289,7 +296,7 @@ func (a *AzureServiceBusQueues) getHandlerFunc(handler bindings.Handler) impl.Ha
Data: msg.Body,
Metadata: metadata,
})
return err
return []impl.HandlerResponseItem{}, err
}
}

View File

@ -1,254 +0,0 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ipfs
import (
"context"
"fmt"
"net"
"net/http"
"os"
"path/filepath"
"strings"
"sync"
"time"
ipfsHttpclient "github.com/ipfs/go-ipfs-http-client"
ipfsIcore "github.com/ipfs/interface-go-ipfs-core"
ipfsConfig "github.com/ipfs/kubo/config"
ipfsCore "github.com/ipfs/kubo/core"
ipfsCoreapi "github.com/ipfs/kubo/core/coreapi"
ipfsLibp2p "github.com/ipfs/kubo/core/node/libp2p"
ipfsLoader "github.com/ipfs/kubo/plugin/loader"
ipfsRepo "github.com/ipfs/kubo/repo"
ipfsFsrepo "github.com/ipfs/kubo/repo/fsrepo"
"github.com/multiformats/go-multiaddr"
"github.com/dapr/components-contrib/bindings"
"github.com/dapr/kit/logger"
)
const swarmKeyFile = "swarm.key"
var (
loadPluginsOnce sync.Once
httpClient *http.Client
)
func init() {
httpClient = &http.Client{
Transport: &http.Transport{
Dial: (&net.Dialer{
Timeout: 5 * time.Second,
}).Dial,
},
}
}
// IPFSBinding is a binding for interacting with an IPFS network.
type IPFSBinding struct {
metadata ipfsMetadata
ipfsAPI ipfsIcore.CoreAPI
ipfsNode *ipfsCore.IpfsNode
ipfsRepo ipfsRepo.Repo
ctx context.Context
cancel context.CancelFunc
logger logger.Logger
}
// NewIPFSBinding returns a new IPFSBinding.
func NewIPFSBinding(logger logger.Logger) bindings.OutputBinding {
return &IPFSBinding{
logger: logger,
}
}
// Init the binding.
func (b *IPFSBinding) Init(metadata bindings.Metadata) (err error) {
b.ctx, b.cancel = context.WithCancel(context.Background())
err = b.metadata.FromMap(metadata.Properties)
if err != nil {
return err
}
if b.metadata.ExternalAPI == "" {
var onceErr error
loadPluginsOnce.Do(func() {
onceErr = setupPlugins("")
})
if onceErr != nil {
return onceErr
}
err = b.createNode()
if err != nil {
return fmt.Errorf("failed to start IPFS node: %v", err)
}
} else {
if b.metadata.ExternalAPI[0] == '/' {
var maddr multiaddr.Multiaddr
maddr, err = multiaddr.NewMultiaddr(b.metadata.ExternalAPI)
if err != nil {
return fmt.Errorf("failed to parse external API multiaddr: %v", err)
}
b.ipfsAPI, err = ipfsHttpclient.NewApiWithClient(maddr, httpClient)
} else {
b.ipfsAPI, err = ipfsHttpclient.NewURLApiWithClient(b.metadata.ExternalAPI, httpClient)
}
if err != nil {
return fmt.Errorf("failed to initialize external IPFS API: %v", err)
}
b.logger.Infof("Using IPFS APIs at %s", b.metadata.ExternalAPI)
}
return nil
}
func (b *IPFSBinding) Close() (err error) {
if b.cancel != nil {
b.cancel()
b.cancel = nil
}
if b.ipfsNode != nil {
err = b.ipfsNode.Close()
if err != nil {
b.logger.Errorf("Error while closing IPFS node: %v", err)
}
b.ipfsNode = nil
}
if b.ipfsRepo != nil {
err = b.ipfsRepo.Close()
if err != nil {
b.logger.Errorf("Error while closing IPFS repo: %v", err)
}
b.ipfsRepo = nil
}
return nil
}
func (b *IPFSBinding) createNode() (err error) {
// Init the repo if needed
if !ipfsFsrepo.IsInitialized(b.metadata.RepoPath) {
var cfg *ipfsConfig.Config
cfg, err = b.metadata.IPFSConfig()
if err != nil {
return err
}
err = ipfsFsrepo.Init(b.metadata.RepoPath, cfg)
if err != nil {
return err
}
if b.metadata.SwarmKey != "" {
skPath := filepath.Join(b.metadata.RepoPath, swarmKeyFile)
err = os.WriteFile(skPath, []byte(b.metadata.SwarmKey), 0o600)
if err != nil {
return fmt.Errorf("error writing swarm key to file '%s': %v", skPath, err)
}
}
b.logger.Infof("Initialized a new IPFS repo at path %s", b.metadata.RepoPath)
}
// Open the repo
repo, err := ipfsFsrepo.Open(b.metadata.RepoPath)
if err != nil {
return err
}
b.logger.Infof("Opened IPFS repo at path %s", b.metadata.RepoPath)
// Create the node
nodeOptions := &ipfsCore.BuildCfg{
Online: true,
Repo: repo,
}
r := strings.ToLower(b.metadata.Routing)
switch r {
case "", "dht":
nodeOptions.Routing = ipfsLibp2p.DHTOption
case "dhtclient":
nodeOptions.Routing = ipfsLibp2p.DHTClientOption
case "dhtserver":
nodeOptions.Routing = ipfsLibp2p.DHTServerOption
case "none":
nodeOptions.Routing = ipfsLibp2p.NilRouterOption
default:
return fmt.Errorf("invalid value for metadata property 'routing'")
}
b.ipfsNode, err = ipfsCore.NewNode(b.ctx, nodeOptions)
if err != nil {
return err
}
b.logger.Infof("Started IPFS node %s", b.ipfsNode.Identity)
// Init API
b.ipfsAPI, err = ipfsCoreapi.NewCoreAPI(b.ipfsNode)
if err != nil {
return err
}
return nil
}
// Operations returns the supported operations for this binding.
func (b *IPFSBinding) Operations() []bindings.OperationKind {
return []bindings.OperationKind{
bindings.GetOperation,
bindings.CreateOperation, // alias for "add"
bindings.ListOperation, // alias for "ls"
bindings.DeleteOperation, // alias for "pin-rm"
"add",
"ls",
"pin-add",
"pin-rm",
"pin-ls",
}
}
// Invoke performs an HTTP request to the configured HTTP endpoint.
func (b *IPFSBinding) Invoke(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
switch req.Operation {
case bindings.GetOperation:
return b.getOperation(ctx, req)
case "add", bindings.CreateOperation:
return b.addOperation(ctx, req)
case "ls", bindings.ListOperation:
return b.lsOperation(ctx, req)
case "pin-add":
return b.pinAddOperation(ctx, req)
case "pin-ls":
return b.pinLsOperation(ctx, req)
case "pin-rm", bindings.DeleteOperation:
return b.pinRmOperation(ctx, req)
}
return &bindings.InvokeResponse{
Data: nil,
Metadata: nil,
}, nil
}
func setupPlugins(externalPluginsPath string) error {
plugins, err := ipfsLoader.NewPluginLoader("")
if err != nil {
return fmt.Errorf("error loading plugins: %s", err)
}
if err := plugins.Initialize(); err != nil {
return fmt.Errorf("error initializing plugins: %s", err)
}
if err := plugins.Inject(); err != nil {
return fmt.Errorf("error initializing plugins: %s", err)
}
return nil
}

View File

@ -1,425 +0,0 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ipfs
import (
"context"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"log"
"os"
"reflect"
"sort"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/dapr/components-contrib/bindings"
"github.com/dapr/components-contrib/internal/utils"
"github.com/dapr/components-contrib/metadata"
"github.com/dapr/kit/logger"
)
func TestMain(m *testing.M) {
if !utils.IsTruthy(os.Getenv("IPFS_TEST")) {
log.Println("IPFS_TEST env var is not set to a truthy value; skipping tests")
os.Exit(0)
}
os.Exit(m.Run())
}
func TestSingleNodeGlobalNetwork(t *testing.T) {
var b *IPFSBinding
repoPath := t.TempDir()
// CIDS contained in the QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG folder
folderCids := []string{
"QmZTR5bcpQD7cFgTorqxZDYaew1Wqgfbd2ud9QqGPAkK2V",
"QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y",
"QmY5heUM5qgRubMDD1og9fhCPA6QdkMp3QCwd4s7gJsyE7",
"QmdncfsVm2h5Kqq9hPmU7oAVX2zTSVP3L869tgTbPYnsha",
"QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB",
"QmTumTjvcYCAvRRwQ8sDRxh8ezmrcr88YFU7iYNroGGTBZ",
}
sort.Strings(folderCids)
t.Run("init node", func(t *testing.T) {
b = NewIPFSBinding(logger.NewLogger("tests")).(*IPFSBinding)
err := b.Init(bindings.Metadata{Base: metadata.Base{
Properties: map[string]string{
"repoPath": repoPath,
"routing": "dhtclient",
},
}})
require.NoError(t, err)
})
t.Run("get operation", func(t *testing.T) {
t.Run("empty path", func(t *testing.T) {
_, err := b.Invoke(context.Background(), &bindings.InvokeRequest{
Operation: "get",
})
if assert.Error(t, err) {
assert.Equal(t, err.Error(), "metadata property 'path' is empty")
}
})
t.Run("retrieve document by CID", func(t *testing.T) {
data := getDocument(t, b, "QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB")
compareHash(t, data, "a48161fca5edd15f4649bb928c10769216fccdf317265fc75d747c1e6892f53c")
})
t.Run("retrieve document by IPLD", func(t *testing.T) {
// Same document, but different addressing method
data := getDocument(t, b, "/ipfs/QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG/readme")
compareHash(t, data, "a48161fca5edd15f4649bb928c10769216fccdf317265fc75d747c1e6892f53c")
})
t.Run("cannot retrieve folder", func(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
_, err := b.Invoke(ctx, &bindings.InvokeRequest{
Operation: "get",
Metadata: map[string]string{
"path": "/ipfs/QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG",
},
})
if assert.Error(t, err) {
assert.Equal(t, err.Error(), "path does not represent a file")
}
})
// Retrieve files also to speed up pinning later
t.Run("retrieve files", func(t *testing.T) {
for _, e := range folderCids {
getDocument(t, b, e)
}
getDocument(t, b, "QmdytmR4wULMd3SLo6ePF4s3WcRHWcpnJZ7bHhoj3QB13v")
})
})
t.Run("ls operation", func(t *testing.T) {
t.Run("empty path", func(t *testing.T) {
_, err := b.Invoke(context.Background(), &bindings.InvokeRequest{
Operation: "ls",
})
if assert.Error(t, err) {
assert.Equal(t, err.Error(), "metadata property 'path' is empty")
}
})
testLsOperationResponse := func(t *testing.T, list lsOperationResponse) {
cids := make([]string, len(list))
for i, e := range list {
cids[i] = e.Cid
}
sort.Strings(cids)
assert.True(t, reflect.DeepEqual(cids, folderCids), "received='%v' expected='%v'", cids, folderCids)
}
t.Run("list by CID", func(t *testing.T) {
list := listPath(t, b, "QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG")
require.NotEmpty(t, list)
testLsOperationResponse(t, list)
})
t.Run("list by IPLD", func(t *testing.T) {
list := listPath(t, b, "/ipfs/QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG")
require.NotEmpty(t, list)
testLsOperationResponse(t, list)
})
})
t.Run("pin operations", func(t *testing.T) {
t.Run("pin-ls: nothing is pinned on a new node", func(t *testing.T) {
list := listPins(t, b)
assert.Empty(t, list)
})
t.Run("pin-add: pin file by CID", func(t *testing.T) {
res, err := b.Invoke(context.Background(), &bindings.InvokeRequest{
Operation: "pin-add",
Metadata: map[string]string{
"path": "QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB",
},
})
require.NoError(t, err)
require.NotNil(t, res)
require.Empty(t, res.Data)
})
t.Run("pin-ls: list added pin", func(t *testing.T) {
list := listPins(t, b)
assert.Len(t, list, 1)
assert.Equal(t, "QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB", list[0].Cid)
})
t.Run("pin-add: pin file by IPLD", func(t *testing.T) {
res, err := b.Invoke(context.Background(), &bindings.InvokeRequest{
Operation: "pin-add",
Metadata: map[string]string{
"path": "/ipfs/QmdytmR4wULMd3SLo6ePF4s3WcRHWcpnJZ7bHhoj3QB13v",
},
})
require.NoError(t, err)
require.NotNil(t, res)
require.Empty(t, res.Data)
})
t.Run("pin-add: recursively pin folder", func(t *testing.T) {
res, err := b.Invoke(context.Background(), &bindings.InvokeRequest{
Operation: "pin-add",
Metadata: map[string]string{
"path": "QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG",
},
})
require.NoError(t, err)
require.NotNil(t, res)
require.Empty(t, res.Data)
})
// Add the folder to the list of expected items
expect := make([]string, len(folderCids)+2)
expect[0] = "QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG"
expect[1] = "QmdytmR4wULMd3SLo6ePF4s3WcRHWcpnJZ7bHhoj3QB13v"
copy(expect[2:], folderCids)
sort.Strings(expect)
t.Run("pin-ls: list added folder", func(t *testing.T) {
cids := listPinnedCids(t, b)
assert.True(t, reflect.DeepEqual(cids, expect), "received='%v' expected='%v'", cids, expect)
})
t.Run("pin-rm: remove file", func(t *testing.T) {
res, err := b.Invoke(context.Background(), &bindings.InvokeRequest{
Operation: "pin-rm",
Metadata: map[string]string{
"path": "QmdytmR4wULMd3SLo6ePF4s3WcRHWcpnJZ7bHhoj3QB13v",
},
})
require.NoError(t, err)
require.NotNil(t, res)
require.Empty(t, res.Data)
})
// Remove the un-pinned file
i := 0
for _, e := range expect {
if e != "QmdytmR4wULMd3SLo6ePF4s3WcRHWcpnJZ7bHhoj3QB13v" {
expect[i] = e
i++
}
}
expect = expect[:i]
t.Run("pin-ls: updated after removed file", func(t *testing.T) {
cids := listPinnedCids(t, b)
assert.True(t, reflect.DeepEqual(cids, expect), "received='%v' expected='%v'", cids, expect)
})
t.Run("pin-rm: recursively remove folder", func(t *testing.T) {
res, err := b.Invoke(context.Background(), &bindings.InvokeRequest{
Operation: "pin-rm",
Metadata: map[string]string{
"path": "QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG",
},
})
require.NoError(t, err)
require.NotNil(t, res)
require.Empty(t, res.Data)
})
t.Run("pin-rm: remove explicitly-pinned file", func(t *testing.T) {
res, err := b.Invoke(context.Background(), &bindings.InvokeRequest{
Operation: "pin-rm",
Metadata: map[string]string{
"path": "QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB",
},
})
require.NoError(t, err)
require.NotNil(t, res)
require.Empty(t, res.Data)
})
t.Run("pin-ls: updated list is empty", func(t *testing.T) {
list := listPins(t, b)
assert.Empty(t, list)
})
})
t.Run("create operation", func(t *testing.T) {
expectPins := []string{}
t.Run("add with default options", func(t *testing.T) {
path := addDocument(t, b,
[]byte("Quel ramo del lago di Como, che volge a mezzogiorno"),
nil,
)
assert.Equal(t, "/ipfs/QmRW7jvkePyaAFvtapaqZ9kNkziUrmkhi4ue5oNpXS2qUx", path)
expectPins = append(expectPins, "QmRW7jvkePyaAFvtapaqZ9kNkziUrmkhi4ue5oNpXS2qUx")
})
t.Run("add with CID v1", func(t *testing.T) {
path := addDocument(t, b,
[]byte("Quel ramo del lago di Como, che volge a mezzogiorno"),
map[string]string{"cidVersion": "1"},
)
assert.Equal(t, "/ipfs/bafkreidhuwuwgycmsbj4sesi3pm6vpxpbm6byt3twex7sc2nadaxksnqeq", path)
expectPins = append(expectPins, "bafkreidhuwuwgycmsbj4sesi3pm6vpxpbm6byt3twex7sc2nadaxksnqeq")
})
t.Run("added files are pinned", func(t *testing.T) {
cids := listPinnedCids(t, b)
assert.True(t, reflect.DeepEqual(cids, expectPins), "received='%v' expected='%v'", cids, expectPins)
})
t.Run("add without pinning", func(t *testing.T) {
path := addDocument(t, b,
[]byte("😁🐶"),
map[string]string{"pin": "false"},
)
assert.Equal(t, "/ipfs/QmWsLpV1UUD26qHaEJqXfHazSRRZVX82M51EQ87UT7ryiR", path)
})
t.Run("pinned documents haven't changed", func(t *testing.T) {
cids := listPinnedCids(t, b)
assert.True(t, reflect.DeepEqual(cids, expectPins), "received='%v' expected='%v'", cids, expectPins)
})
t.Run("add inline", func(t *testing.T) {
path := addDocument(t, b,
[]byte("😁🐶"),
map[string]string{"inline": "true"},
)
assert.Equal(t, "/ipfs/bafyaaeakbyeaeeqi6cpzrapqt6ilmgai", path)
})
})
if b != nil {
b.Close()
}
}
func getDocument(t *testing.T, b *IPFSBinding, path string) []byte {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
res, err := b.Invoke(ctx, &bindings.InvokeRequest{
Operation: "get",
Metadata: map[string]string{
"path": path,
},
})
require.NoError(t, err)
require.NotNil(t, res)
require.NotEmpty(t, res.Data)
return res.Data
}
func listPath(t *testing.T, b *IPFSBinding, path string) lsOperationResponse {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
res, err := b.Invoke(ctx, &bindings.InvokeRequest{
Operation: "ls",
Metadata: map[string]string{
"path": path,
},
})
require.NoError(t, err)
require.NotNil(t, res)
require.NotEmpty(t, res.Data)
list := lsOperationResponse{}
err = json.Unmarshal(res.Data, &list)
require.NoError(t, err)
return list
}
func listPins(t *testing.T, b *IPFSBinding) pinLsOperationResponse {
res, err := b.Invoke(context.Background(), &bindings.InvokeRequest{
Operation: "pin-ls",
})
require.NoError(t, err)
require.NotNil(t, res)
require.NotEmpty(t, res.Data)
list := pinLsOperationResponse{}
err = json.Unmarshal(res.Data, &list)
require.NoError(t, err)
return list
}
func listPinnedCids(t *testing.T, b *IPFSBinding) []string {
list := listPins(t, b)
require.NotEmpty(t, list)
cids := make([]string, len(list))
for i, e := range list {
cids[i] = e.Cid
}
sort.Strings(cids)
return cids
}
func addDocument(t *testing.T, b *IPFSBinding, data []byte, metadata map[string]string) string {
res, err := b.Invoke(context.Background(), &bindings.InvokeRequest{
Operation: "create",
Data: data,
Metadata: metadata,
})
require.NoError(t, err)
require.NotNil(t, res)
require.NotEmpty(t, res.Data)
o := addOperationResponse{}
err = json.Unmarshal(res.Data, &o)
require.NoError(t, err)
require.NotEmpty(t, o.Path)
return o.Path
}
func compareHash(t *testing.T, data []byte, expect string) {
require.NotEmpty(t, data)
h := sha256.Sum256(data)
digest := hex.EncodeToString(h[:])
assert.Equal(t, expect, digest)
}

View File

@ -1,130 +0,0 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ipfs
import (
"fmt"
"io"
"strings"
ipfsOptions "github.com/ipfs/interface-go-ipfs-core/options"
ipfsConfig "github.com/ipfs/kubo/config"
ipfsFsrepo "github.com/ipfs/kubo/repo/fsrepo"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/dapr/components-contrib/metadata"
)
type ipfsMetadata struct {
// Path where to store the IPFS repository
// It will be initialized automatically if needed
// Defaults to the "best known path" set by IPFS
RepoPath string `mapstructure:"repoPath"`
// If set, uses an external IPFS daemon, connecting to its APIs
// Can be a HTTP(S) address or a multi-address
// If set, a local node will not be initialized
ExternalAPI string `mapstructure:"externalAPI"`
// The options below can only be set when a new local repo is being initialized
// List of bootstrap nodes, as a comma-separated string
// If empty, defaults to the official bootstrap nodes provided by the IPFS project
// Users should not modify this unless they're using a private cluster
BootstrapNodes string `mapstructure:"bootstrapNodes"`
// Swarm key to use for connecting to private IPFS networks
// If empty, the node will connect to the default, public IPFS network
// Generate with https://github.com/Kubuxu/go-ipfs-swarm-key-gen
// When using a swarm key, users should also configure the bootstrap nodes
SwarmKey string `mapstructure:"swarmKey"`
// Routing mode: "dht" (default) or "dhtclient"
Routing string `mapstructure:"routing"`
// Max local storage used
// Default: the default value used by go-ipfs (currently, "10GB")
StorageMax string `mapstructure:"storageMax"`
// Watermark for running garbage collection, 0-100 (as a percentage)
// Default: the default value used by go-ipfs (currently, 90)
StorageGCWatermark int64 `mapstructure:"storageGCWatermark"`
// Interval for running garbage collection
// Default: the default value used by go-ipfs (currently, "1h")
StorageGCPeriod string `mapstructure:"storageGCPeriod"`
}
// FromMap initializes the metadata object from a map.
func (m *ipfsMetadata) FromMap(mp map[string]string) (err error) {
if len(mp) > 0 {
err = metadata.DecodeMetadata(mp, m)
if err != nil {
return err
}
}
if m.RepoPath == "" {
m.RepoPath, err = ipfsFsrepo.BestKnownPath()
if err != nil {
return fmt.Errorf("error determining the best known repo path: %v", err)
}
}
return nil
}
// IPFSConfig returns the configuration object for using with the go-ipfs library.
// This is executed only when initializing a new repository.
func (m *ipfsMetadata) IPFSConfig() (*ipfsConfig.Config, error) {
identity, err := ipfsConfig.CreateIdentity(io.Discard, []ipfsOptions.KeyGenerateOption{
ipfsOptions.Key.Type(ipfsOptions.Ed25519Key),
})
if err != nil {
return nil, err
}
cfg, err := ipfsConfig.InitWithIdentity(identity)
if err != nil {
return nil, err
}
if m.BootstrapNodes != "" {
var peers []peer.AddrInfo
peers, err = ipfsConfig.ParseBootstrapPeers(
strings.Split(m.BootstrapNodes, ","),
)
if err != nil {
return nil, fmt.Errorf("invalid value for metadata property 'bootstrapNodes': %v", err)
}
cfg.SetBootstrapPeers(peers)
}
r := strings.ToLower(m.Routing)
switch r {
case "dht", "dhtclient", "dhtserver", "none":
cfg.Routing.Type = ipfsConfig.NewOptionalString(r)
case "":
cfg.Routing.Type = ipfsConfig.NewOptionalString("dht")
default:
return nil, fmt.Errorf("invalid value for metadata property 'routing'")
}
if m.StorageMax != "" {
cfg.Datastore.StorageMax = m.StorageMax
}
if m.StorageGCWatermark != 0 {
cfg.Datastore.StorageGCWatermark = m.StorageGCWatermark
}
if m.StorageGCPeriod != "" {
cfg.Datastore.GCPeriod = m.StorageGCPeriod
}
return cfg, nil
}

View File

@ -1,112 +0,0 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ipfs
import (
"context"
"encoding/json"
"errors"
"fmt"
ipfsFiles "github.com/ipfs/go-ipfs-files"
ipfsOptions "github.com/ipfs/interface-go-ipfs-core/options"
"github.com/multiformats/go-multihash"
"github.com/dapr/components-contrib/bindings"
"github.com/dapr/components-contrib/metadata"
)
// Handler for the "add" operation, which adds a new file
func (b *IPFSBinding) addOperation(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
if len(req.Data) == 0 {
return nil, errors.New("data is empty")
}
reqMetadata := &addRequestMetadata{}
err := reqMetadata.FromMap(req.Metadata)
if err != nil {
return nil, err
}
opts, err := reqMetadata.UnixfsAddOptions()
if err != nil {
return nil, err
}
f := ipfsFiles.NewBytesFile(req.Data)
resolved, err := b.ipfsAPI.Unixfs().Add(ctx, f, opts...)
if err != nil {
return nil, err
}
res := addOperationResponse{
Path: resolved.String(),
}
enc, err := json.Marshal(res)
if err != nil {
return nil, err
}
return &bindings.InvokeResponse{
Data: enc,
Metadata: nil,
}, nil
}
type addOperationResponse struct {
Path string `json:"path"`
}
type addRequestMetadata struct {
CidVersion *int `mapstructure:"cidVersion"`
Pin *bool `mapstructure:"pin"`
Hash *string `mapstructure:"hash"`
Inline *bool `mapstructure:"inline"`
InlineLimit *int `mapstructure:"inlineLimit"`
}
func (m *addRequestMetadata) FromMap(mp map[string]string) (err error) {
if len(mp) > 0 {
err = metadata.DecodeMetadata(mp, m)
if err != nil {
return err
}
}
return nil
}
func (m *addRequestMetadata) UnixfsAddOptions() ([]ipfsOptions.UnixfsAddOption, error) {
opts := []ipfsOptions.UnixfsAddOption{}
if m.CidVersion != nil {
opts = append(opts, ipfsOptions.Unixfs.CidVersion(*m.CidVersion))
}
if m.Pin != nil {
opts = append(opts, ipfsOptions.Unixfs.Pin(*m.Pin))
} else {
opts = append(opts, ipfsOptions.Unixfs.Pin(true))
}
if m.Hash != nil {
hash, ok := multihash.Names[*m.Hash]
if !ok {
return nil, fmt.Errorf("invalid hash %s", *m.Hash)
}
opts = append(opts, ipfsOptions.Unixfs.Hash(hash))
}
if m.Inline != nil {
opts = append(opts, ipfsOptions.Unixfs.Inline(*m.Inline))
}
if m.InlineLimit != nil {
opts = append(opts, ipfsOptions.Unixfs.InlineLimit(*m.InlineLimit))
}
return opts, nil
}

View File

@ -1,80 +0,0 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ipfs
import (
"context"
"errors"
"fmt"
"io"
ipfsFiles "github.com/ipfs/go-ipfs-files"
ipfsPath "github.com/ipfs/interface-go-ipfs-core/path"
"github.com/dapr/components-contrib/bindings"
"github.com/dapr/components-contrib/metadata"
)
// Handler for the "get" operation, which retrieves a document
func (b *IPFSBinding) getOperation(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
reqMetadata := &getRequestMetadata{}
err := reqMetadata.FromMap(req.Metadata)
if err != nil {
return nil, err
}
if reqMetadata.Path == "" {
return nil, errors.New("metadata property 'path' is empty")
}
p := ipfsPath.New(reqMetadata.Path)
err = p.IsValid()
if err != nil {
return nil, fmt.Errorf("invalid value for metadata property 'path': %v", err)
}
res, err := b.ipfsAPI.Unixfs().Get(ctx, p)
if err != nil {
return nil, err
}
defer res.Close()
f, ok := res.(ipfsFiles.File)
if !ok {
return nil, errors.New("path does not represent a file")
}
data, err := io.ReadAll(f)
if err != nil {
return nil, err
}
return &bindings.InvokeResponse{
Data: data,
Metadata: nil,
}, nil
}
type getRequestMetadata struct {
Path string `mapstructure:"path"`
}
func (m *getRequestMetadata) FromMap(mp map[string]string) (err error) {
if len(mp) > 0 {
err = metadata.DecodeMetadata(mp, m)
if err != nil {
return err
}
}
return nil
}

View File

@ -1,91 +0,0 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ipfs
import (
"context"
"encoding/json"
"errors"
"fmt"
ipfsPath "github.com/ipfs/interface-go-ipfs-core/path"
"github.com/dapr/components-contrib/bindings"
"github.com/dapr/components-contrib/metadata"
)
// Handler for the "ls" operation, which retrieves a document
func (b *IPFSBinding) lsOperation(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
reqMetadata := &lsRequestMetadata{}
err := reqMetadata.FromMap(req.Metadata)
if err != nil {
return nil, err
}
if reqMetadata.Path == "" {
return nil, errors.New("metadata property 'path' is empty")
}
p := ipfsPath.New(reqMetadata.Path)
err = p.IsValid()
if err != nil {
return nil, fmt.Errorf("invalid value for metadata property 'path': %v", err)
}
ls, err := b.ipfsAPI.Unixfs().Ls(ctx, p)
if err != nil {
return nil, err
}
res := lsOperationResponse{}
for e := range ls {
if e.Err != nil {
return nil, e.Err
}
res = append(res, lsOperationResponseItem{
Name: e.Name,
Size: e.Size,
Type: e.Type.String(),
Cid: e.Cid.String(),
})
}
j, _ := json.Marshal(res)
return &bindings.InvokeResponse{
Data: j,
Metadata: nil,
}, nil
}
type lsOperationResponseItem struct {
Name string `json:"name,omitempty"`
Size uint64 `json:"size,omitempty"`
Cid string `json:"cid,omitempty"`
Type string `json:"type,omitempty"`
}
type lsOperationResponse []lsOperationResponseItem
type lsRequestMetadata struct {
Path string `mapstructure:"path"`
}
func (m *lsRequestMetadata) FromMap(mp map[string]string) (err error) {
if len(mp) > 0 {
err = metadata.DecodeMetadata(mp, m)
if err != nil {
return err
}
}
return nil
}

View File

@ -1,83 +0,0 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ipfs
import (
"context"
"errors"
"fmt"
ipfsOptions "github.com/ipfs/interface-go-ipfs-core/options"
ipfsPath "github.com/ipfs/interface-go-ipfs-core/path"
"github.com/dapr/components-contrib/bindings"
"github.com/dapr/components-contrib/metadata"
)
// Handler for the "pin-add" operation, which adds a new pin
func (b *IPFSBinding) pinAddOperation(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
reqMetadata := &pinAddRequestMetadata{}
err := reqMetadata.FromMap(req.Metadata)
if err != nil {
return nil, err
}
if reqMetadata.Path == "" {
return nil, errors.New("metadata property 'path' is empty")
}
p := ipfsPath.New(reqMetadata.Path)
err = p.IsValid()
if err != nil {
return nil, fmt.Errorf("invalid value for metadata property 'path': %v", err)
}
opts, err := reqMetadata.PinAddOptions()
if err != nil {
return nil, err
}
err = b.ipfsAPI.Pin().Add(ctx, p, opts...)
if err != nil {
return nil, err
}
return &bindings.InvokeResponse{
Data: nil,
Metadata: nil,
}, nil
}
type pinAddRequestMetadata struct {
Path string `mapstructure:"path"`
Recursive *bool `mapstructure:"recursive"`
}
func (m *pinAddRequestMetadata) FromMap(mp map[string]string) (err error) {
if len(mp) > 0 {
err = metadata.DecodeMetadata(mp, m)
if err != nil {
return err
}
}
return nil
}
func (m *pinAddRequestMetadata) PinAddOptions() ([]ipfsOptions.PinAddOption, error) {
opts := []ipfsOptions.PinAddOption{}
if m.Recursive != nil {
opts = append(opts, ipfsOptions.Pin.Recursive(*m.Recursive))
} else {
opts = append(opts, ipfsOptions.Pin.Recursive(true))
}
return opts, nil
}

View File

@ -1,104 +0,0 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ipfs
import (
"context"
"encoding/json"
"fmt"
"strings"
ipfsOptions "github.com/ipfs/interface-go-ipfs-core/options"
"github.com/dapr/components-contrib/bindings"
"github.com/dapr/components-contrib/metadata"
)
// Handler for the "pin-ls" operation, which removes a pin
func (b *IPFSBinding) pinLsOperation(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
reqMetadata := &pinLsRequestMetadata{}
err := reqMetadata.FromMap(req.Metadata)
if err != nil {
return nil, err
}
opts, err := reqMetadata.PinLsOptions()
if err != nil {
return nil, err
}
ls, err := b.ipfsAPI.Pin().Ls(ctx, opts...)
if err != nil {
return nil, err
}
res := pinLsOperationResponse{}
for e := range ls {
err = e.Err()
if err != nil {
return nil, err
}
res = append(res, pinLsOperationResponseItem{
Type: e.Type(),
Cid: e.Path().Cid().String(),
})
}
j, _ := json.Marshal(res)
return &bindings.InvokeResponse{
Data: j,
Metadata: nil,
}, nil
}
type pinLsOperationResponseItem struct {
Cid string `json:"cid,omitempty"`
Type string `json:"type,omitempty"`
}
type pinLsOperationResponse []pinLsOperationResponseItem
type pinLsRequestMetadata struct {
Type *string `mapstructure:"type"`
}
func (m *pinLsRequestMetadata) FromMap(mp map[string]string) (err error) {
if len(mp) > 0 {
err = metadata.DecodeMetadata(mp, m)
if err != nil {
return err
}
}
return nil
}
func (m *pinLsRequestMetadata) PinLsOptions() ([]ipfsOptions.PinLsOption, error) {
opts := []ipfsOptions.PinLsOption{}
if m.Type != nil {
switch strings.ToLower(*m.Type) {
case "direct":
opts = append(opts, ipfsOptions.Pin.Ls.Direct())
case "recursive":
opts = append(opts, ipfsOptions.Pin.Ls.Recursive())
case "indirect":
opts = append(opts, ipfsOptions.Pin.Ls.Indirect())
case "all":
opts = append(opts, ipfsOptions.Pin.Ls.All())
default:
return nil, fmt.Errorf("invalid value for metadata property 'type'")
}
} else {
opts = append(opts, ipfsOptions.Pin.Ls.All())
}
return opts, nil
}

View File

@ -1,83 +0,0 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ipfs
import (
"context"
"errors"
"fmt"
ipfsOptions "github.com/ipfs/interface-go-ipfs-core/options"
ipfsPath "github.com/ipfs/interface-go-ipfs-core/path"
"github.com/dapr/components-contrib/bindings"
"github.com/dapr/components-contrib/metadata"
)
// Handler for the "pin-rm" operation, which removes a pin
func (b *IPFSBinding) pinRmOperation(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
reqMetadata := &pinRmRequestMetadata{}
err := reqMetadata.FromMap(req.Metadata)
if err != nil {
return nil, err
}
if reqMetadata.Path == "" {
return nil, errors.New("metadata property 'path' is empty")
}
p := ipfsPath.New(reqMetadata.Path)
err = p.IsValid()
if err != nil {
return nil, fmt.Errorf("invalid value for metadata property 'path': %v", err)
}
opts, err := reqMetadata.PinRmOptions()
if err != nil {
return nil, err
}
err = b.ipfsAPI.Pin().Rm(ctx, p, opts...)
if err != nil {
return nil, err
}
return &bindings.InvokeResponse{
Data: nil,
Metadata: nil,
}, nil
}
type pinRmRequestMetadata struct {
Path string `mapstructure:"path"`
Recursive *bool `mapstructure:"recursive"`
}
func (m *pinRmRequestMetadata) FromMap(mp map[string]string) (err error) {
if len(mp) > 0 {
err = metadata.DecodeMetadata(mp, m)
if err != nil {
return err
}
}
return nil
}
func (m *pinRmRequestMetadata) PinRmOptions() ([]ipfsOptions.PinRmOption, error) {
opts := []ipfsOptions.PinRmOption{}
if m.Recursive != nil {
opts = append(opts, ipfsOptions.Pin.RmRecursive(*m.Recursive))
} else {
opts = append(opts, ipfsOptions.Pin.RmRecursive(true))
}
return opts, nil
}

View File

@ -89,9 +89,12 @@ func (b *Binding) Read(ctx context.Context, handler bindings.Handler) error {
return nil
}
ah := adaptHandler(handler)
handlerConfig := kafka.SubscriptionHandlerConfig{
IsBulkSubscribe: false,
Handler: adaptHandler(handler),
}
for _, t := range b.topics {
b.kafka.AddTopicHandler(t, ah)
b.kafka.AddTopicHandler(t, handlerConfig)
}
go func() {

View File

@ -19,7 +19,7 @@ import (
"strconv"
"time"
"github.com/jackc/pgx/v4/pgxpool"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/pkg/errors"
"github.com/dapr/components-contrib/bindings"
@ -59,7 +59,7 @@ func (p *Postgres) Init(metadata bindings.Metadata) error {
return errors.Wrap(err, "error opening DB connection")
}
p.db, err = pgxpool.ConnectConfig(context.Background(), poolConfig)
p.db, err = pgxpool.NewWithConfig(context.Background(), poolConfig)
if err != nil {
return errors.Wrap(err, "unable to ping the DB")
}

View File

@ -137,7 +137,7 @@ func (r *RabbitMQ) Invoke(ctx context.Context, req *bindings.InvokeRequest) (*bi
pub.Priority = priority
}
err = r.channel.Publish("", r.metadata.QueueName, false, false, pub)
err = r.channel.PublishWithContext(ctx, "", r.metadata.QueueName, false, false, pub)
if err != nil {
return nil, err

236
go.mod
View File

@ -23,7 +23,7 @@ require (
github.com/Azure/go-autorest/autorest/adal v0.9.18
github.com/Azure/go-autorest/autorest/azure/auth v0.5.11
github.com/DATA-DOG/go-sqlmock v1.5.0
github.com/Shopify/sarama v1.30.0
github.com/Shopify/sarama v1.37.2
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
github.com/aerospike/aerospike-client-go v4.5.0+incompatible
github.com/agrea/ptr v0.0.0-20180711073057-77a518d99b7b
@ -47,22 +47,21 @@ require (
github.com/dancannon/gorethink v4.0.0+incompatible
github.com/dapr/kit v0.0.2
github.com/deepmap/oapi-codegen v1.8.1 // indirect
github.com/denisenkom/go-mssqldb v0.0.0-20210411162248-d9abbec934ba
github.com/denisenkom/go-mssqldb v0.12.2
github.com/dghubble/go-twitter v0.0.0-20190719072343-39e5462e111f
github.com/dghubble/oauth1 v0.6.0
github.com/didip/tollbooth v4.0.2+incompatible
github.com/eapache/go-resiliency v1.2.0 // indirect
github.com/eclipse/paho.mqtt.golang v1.3.5
github.com/eapache/go-resiliency v1.3.0 // indirect
github.com/eclipse/paho.mqtt.golang v1.4.1
github.com/fasthttp-contrib/sessions v0.0.0-20160905201309-74f6ac73d5d5
github.com/fatih/color v1.13.0 // indirect
github.com/gavv/httpexpect v2.0.0+incompatible // indirect
github.com/ghodss/yaml v1.0.0
github.com/go-errors/errors v1.4.0 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/go-redis/redis/v8 v8.11.5
github.com/go-sql-driver/mysql v1.6.0
github.com/gocql/gocql v0.0.0-20210515062232-b7ef815b4556
github.com/gocql/gocql v1.2.1
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang/mock v1.6.0
github.com/golang/snappy v0.0.4 // indirect
@ -78,8 +77,7 @@ require (
github.com/imkira/go-interpol v1.1.0 // indirect
github.com/influxdata/influxdb-client-go v1.4.0
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect
github.com/jackc/pgx/v4 v4.17.0
github.com/jcmturner/gofork v1.0.0 // indirect
github.com/jcmturner/gofork v1.7.6 // indirect
github.com/json-iterator/go v1.1.12
github.com/kataras/go-errors v0.0.3 // indirect
github.com/kataras/go-serializer v0.0.4 // indirect
@ -91,9 +89,9 @@ require (
github.com/miekg/dns v1.1.50 // indirect
github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4
github.com/moul/http2curl v1.0.0 // indirect
github.com/nats-io/nats-server/v2 v2.7.4
github.com/nats-io/nats-server/v2 v2.9.2
github.com/nats-io/nats-streaming-server v0.21.2 // indirect
github.com/nats-io/nats.go v1.13.1-0.20220308171302-2f2f6968e98d
github.com/nats-io/nats.go v1.17.0
github.com/nats-io/stan.go v0.8.3
github.com/open-policy-agent/opa v0.43.1
github.com/patrickmn/go-cache v2.1.0+incompatible
@ -116,10 +114,10 @@ require (
github.com/yudai/gojsondiff v1.0.0 // indirect
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect
github.com/yuin/gopher-lua v0.0.0-20200603152657-dc2b0ca8b37e // indirect
go.mongodb.org/mongo-driver v1.5.1
go.mongodb.org/mongo-driver v1.10.3
go.opencensus.io v0.23.0 // indirect
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
golang.org/x/net v0.0.0-20220630215102-69896b714898
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be
golang.org/x/net v0.0.0-20220927171203-f486391704dc
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a
google.golang.org/api v0.74.0
google.golang.org/genproto v0.0.0-20220405205423-9d709892a2bf
@ -160,21 +158,14 @@ require (
github.com/apache/dubbo-go-hessian2 v1.11.0
github.com/huaweicloud/huaweicloud-sdk-go-obs v3.21.12+incompatible
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.0.87
github.com/ipfs/go-ipfs-files v0.1.1
github.com/ipfs/go-ipfs-http-client v0.4.0
github.com/ipfs/interface-go-ipfs-core v0.7.0
github.com/ipfs/kubo v0.15.0-rc1
github.com/jackc/pgx/v5 v5.0.0
github.com/jackc/pgx/v5 v5.0.2
github.com/labd/commercetools-go-sdk v0.3.2
github.com/libp2p/go-libp2p-core v0.19.1
github.com/multiformats/go-multiaddr v0.6.0
github.com/multiformats/go-multihash v0.2.1
github.com/nacos-group/nacos-sdk-go/v2 v2.0.1
github.com/nacos-group/nacos-sdk-go/v2 v2.1.0
github.com/pashagolub/pgxmock/v2 v2.0.0-beta2
github.com/rabbitmq/amqp091-go v1.3.4
github.com/rabbitmq/amqp091-go v1.5.0
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.476
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssm v1.0.476
github.com/wapc/wapc-go v0.5.2
github.com/wapc/wapc-go v0.5.4
go.uber.org/ratelimit v0.2.0
gopkg.in/couchbase/gocb.v1 v1.6.4
)
@ -182,224 +173,64 @@ require (
require gopkg.in/couchbaselabs/jsonx.v1 v1.0.1 // indirect
require (
bazil.org/fuse v0.0.0-20200407214033-5883e5a4b512 // indirect
cloud.google.com/go/compute v1.5.0 // indirect
cloud.google.com/go/iam v0.3.0 // indirect
cloud.google.com/go/kms v1.4.0 // indirect
contrib.go.opencensus.io/exporter/prometheus v0.4.1 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1 // indirect
github.com/RoaringBitmap/roaring v1.1.0 // indirect
github.com/Stebalien/go-bitfield v0.0.1 // indirect
github.com/Workiva/go-datastructures v1.0.53 // indirect
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 // indirect
github.com/agnivade/levenshtein v1.0.1 // indirect
github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a // indirect
github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5 // indirect
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect
github.com/apache/dubbo-getty v1.4.9-0.20220610060150-8af010f3f3dc // indirect
github.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc // indirect
github.com/benbjohnson/clock v1.3.0 // indirect
github.com/bits-and-blooms/bitset v1.2.0 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/ceramicnetwork/go-dag-jose v0.1.0 // indirect
github.com/cheekybits/genny v1.0.0 // indirect
github.com/containerd/cgroups v1.0.4 // indirect
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect
github.com/creasty/defaults v1.5.2 // indirect
github.com/cskr/pubsub v1.0.2 // indirect
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/dgraph-io/badger v1.6.2 // indirect
github.com/dgraph-io/ristretto v0.1.0 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/dubbogo/gost v1.11.25 // indirect
github.com/dubbogo/triple v1.1.8 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/elastic/gosigar v0.14.2 // indirect
github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 // indirect
github.com/flynn/noise v1.0.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/frankban/quicktest v1.14.3 // indirect
github.com/go-kit/kit v0.10.0 // indirect
github.com/go-kit/log v0.2.0 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/validator/v10 v10.11.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/golang/glog v1.0.0 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/hashicorp/go-hclog v1.0.0 // indirect
github.com/huin/goupnp v1.0.3 // indirect
github.com/ipfs/bbloom v0.0.4 // indirect
github.com/ipfs/go-bitfield v1.0.0 // indirect
github.com/ipfs/go-bitswap v0.9.0 // indirect
github.com/ipfs/go-block-format v0.0.3 // indirect
github.com/ipfs/go-blockservice v0.4.0 // indirect
github.com/ipfs/go-cid v0.2.0 // indirect
github.com/ipfs/go-cidutil v0.1.0 // indirect
github.com/ipfs/go-datastore v0.5.1 // indirect
github.com/ipfs/go-delegated-routing v0.3.0 // indirect
github.com/ipfs/go-ds-badger v0.3.0 // indirect
github.com/ipfs/go-ds-flatfs v0.5.1 // indirect
github.com/ipfs/go-ds-leveldb v0.5.0 // indirect
github.com/ipfs/go-ds-measure v0.2.0 // indirect
github.com/ipfs/go-fetcher v1.6.1 // indirect
github.com/ipfs/go-filestore v1.2.0 // indirect
github.com/ipfs/go-fs-lock v0.0.7 // indirect
github.com/ipfs/go-graphsync v0.13.1 // indirect
github.com/ipfs/go-ipfs-blockstore v1.2.0 // indirect
github.com/ipfs/go-ipfs-chunker v0.0.5 // indirect
github.com/ipfs/go-ipfs-cmds v0.8.1 // indirect
github.com/ipfs/go-ipfs-delay v0.0.1 // indirect
github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect
github.com/ipfs/go-ipfs-exchange-interface v0.2.0 // indirect
github.com/ipfs/go-ipfs-exchange-offline v0.3.0 // indirect
github.com/ipfs/go-ipfs-keystore v0.0.2 // indirect
github.com/ipfs/go-ipfs-pinner v0.2.1 // indirect
github.com/ipfs/go-ipfs-posinfo v0.0.1 // indirect
github.com/ipfs/go-ipfs-pq v0.0.2 // indirect
github.com/ipfs/go-ipfs-provider v0.7.1 // indirect
github.com/ipfs/go-ipfs-routing v0.2.1 // indirect
github.com/ipfs/go-ipfs-util v0.0.2 // indirect
github.com/ipfs/go-ipld-cbor v0.0.5 // indirect
github.com/ipfs/go-ipld-format v0.4.0 // indirect
github.com/ipfs/go-ipld-git v0.1.1 // indirect
github.com/ipfs/go-ipld-legacy v0.1.1 // indirect
github.com/ipfs/go-ipns v0.1.2 // indirect
github.com/ipfs/go-log v1.0.5 // indirect
github.com/ipfs/go-log/v2 v2.5.1 // indirect
github.com/ipfs/go-merkledag v0.6.0 // indirect
github.com/ipfs/go-metrics-interface v0.0.1 // indirect
github.com/ipfs/go-mfs v0.2.1 // indirect
github.com/ipfs/go-namesys v0.5.0 // indirect
github.com/ipfs/go-path v0.3.0 // indirect
github.com/ipfs/go-peertaskqueue v0.7.1 // indirect
github.com/ipfs/go-unixfs v0.4.0 // indirect
github.com/ipfs/go-unixfsnode v1.4.0 // indirect
github.com/ipfs/go-verifcid v0.0.2 // indirect
github.com/ipld/edelweiss v0.1.4 // indirect
github.com/ipld/go-codec-dagpb v1.4.1 // indirect
github.com/ipld/go-ipld-prime v0.17.0 // indirect
github.com/jackc/puddle/v2 v2.0.0 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
github.com/jbenet/goprocess v0.1.4 // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
github.com/jcmturner/gokrb5/v8 v8.4.2 // indirect
github.com/jcmturner/gokrb5/v8 v8.4.3 // indirect
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/jinzhu/copier v0.3.5 // indirect
github.com/k0kubun/pp v3.0.1+incompatible // indirect
github.com/klauspost/cpuid/v2 v2.0.14 // indirect
github.com/knadh/koanf v1.4.1 // indirect
github.com/koron/go-ssdp v0.0.3 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/libp2p/go-cidranger v1.1.0 // indirect
github.com/libp2p/go-doh-resolver v0.4.0 // indirect
github.com/libp2p/go-eventbus v0.2.1 // indirect
github.com/libp2p/go-flow-metrics v0.0.3 // indirect
github.com/libp2p/go-libp2p v0.21.0 // indirect
github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect
github.com/libp2p/go-libp2p-discovery v0.7.0 // indirect
github.com/libp2p/go-libp2p-kad-dht v0.17.0 // indirect
github.com/libp2p/go-libp2p-kbucket v0.4.7 // indirect
github.com/libp2p/go-libp2p-loggables v0.1.0 // indirect
github.com/libp2p/go-libp2p-peerstore v0.7.1 // indirect
github.com/libp2p/go-libp2p-pubsub v0.6.1 // indirect
github.com/libp2p/go-libp2p-pubsub-router v0.5.0 // indirect
github.com/libp2p/go-libp2p-record v0.1.3 // indirect
github.com/libp2p/go-libp2p-resource-manager v0.5.3 // indirect
github.com/libp2p/go-libp2p-routing-helpers v0.2.3 // indirect
github.com/libp2p/go-libp2p-xor v0.1.0 // indirect
github.com/libp2p/go-mplex v0.7.0 // indirect
github.com/libp2p/go-msgio v0.2.0 // indirect
github.com/libp2p/go-nat v0.1.0 // indirect
github.com/libp2p/go-netroute v0.2.0 // indirect
github.com/libp2p/go-openssl v0.0.7 // indirect
github.com/libp2p/go-reuseport v0.2.0 // indirect
github.com/libp2p/go-yamux/v3 v3.1.2 // indirect
github.com/libp2p/zeroconf/v2 v2.1.1 // indirect
github.com/lucas-clemente/quic-go v0.28.0 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect
github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1 // indirect
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/montanaflynn/stats v0.6.6 // indirect
github.com/mschoch/smat v0.2.0 // indirect
github.com/multiformats/go-base32 v0.0.4 // indirect
github.com/multiformats/go-base36 v0.1.0 // indirect
github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
github.com/multiformats/go-multibase v0.1.1 // indirect
github.com/multiformats/go-multicodec v0.5.0 // indirect
github.com/multiformats/go-multistream v0.3.3 // indirect
github.com/multiformats/go-varint v0.0.6 // indirect
github.com/natefinch/lumberjack v2.0.0+incompatible // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 // indirect
github.com/openzipkin/zipkin-go v0.4.0 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect
github.com/pierrec/lz4/v4 v4.1.17 // indirect
github.com/prometheus/statsd_exporter v0.21.0 // indirect
github.com/raulk/go-watchdog v1.3.0 // indirect
github.com/rs/cors v1.7.0 // indirect
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect
github.com/shirou/gopsutil v3.20.11+incompatible // indirect
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
github.com/spf13/viper v1.10.0 // indirect
github.com/stathat/consistent v1.0.0 // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/vektah/gqlparser/v2 v2.4.6 // indirect
github.com/wI2L/jsondiff v0.2.0 // indirect
github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect
github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2 // indirect
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
go.opentelemetry.io/otel v1.7.0 // indirect
go.opentelemetry.io/otel/exporters/jaeger v1.7.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.7.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.7.0 // indirect
go.opentelemetry.io/otel/exporters/zipkin v1.7.0 // indirect
go.opentelemetry.io/otel/sdk v1.7.0 // indirect
go.opentelemetry.io/otel/trace v1.7.0 // indirect
go.opentelemetry.io/proto/otlp v0.16.0 // indirect
go.uber.org/dig v1.14.1 // indirect
go.uber.org/fx v1.17.1 // indirect
go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/tools v0.1.11 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
lukechampine.com/blake3 v1.1.7 // indirect
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
)
@ -424,7 +255,7 @@ require (
github.com/alibabacloud-go/openapi-util v0.0.10 // indirect
github.com/alibabacloud-go/tea-utils v1.4.3
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.61.18 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704 // indirect
github.com/aliyun/credentials-go v1.1.2 // indirect
github.com/aliyunmq/mq-http-go-sdk v1.0.3 // indirect
github.com/apache/pulsar-client-go v0.8.1
@ -448,7 +279,6 @@ require (
github.com/eapache/queue v1.1.0 // indirect
github.com/emirpasic/gods v1.12.0 // indirect
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gofrs/uuid v4.0.0+incompatible // indirect
@ -470,19 +300,13 @@ require (
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/hashicorp/go-uuid v1.0.2 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/serf v0.9.6 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.13.0 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/pgtype v1.12.0 // indirect
github.com/jackc/puddle v1.2.1 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/klauspost/compress v1.15.1 // indirect
github.com/klauspost/compress v1.15.11 // indirect
github.com/linkedin/goavro/v2 v2.9.8 // indirect
github.com/mattn/go-ieproxy v0.0.1 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
@ -491,7 +315,7 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/nats-io/jwt/v2 v2.2.1-0.20220113022732-58e87895b296 // indirect
github.com/nats-io/jwt/v2 v2.3.0 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
@ -510,25 +334,25 @@ require (
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.4.0 // indirect
github.com/tetratelabs/wazero v1.0.0-pre.1 // indirect
github.com/tetratelabs/wazero v1.0.0-pre.2 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tjfoc/gmsm v1.3.2 // indirect
github.com/tklauser/go-sysconf v0.3.6 // indirect
github.com/tklauser/numcpus v0.2.2 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.0.2
github.com/xdg-go/stringprep v1.0.2 // indirect
github.com/xdg-go/scram v1.1.1
github.com/xdg-go/stringprep v1.0.3 // indirect
github.com/yashtewari/glob-intersection v0.1.0 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
go.uber.org/atomic v1.9.0
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 // indirect
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.0 // indirect

1323
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -27,22 +27,29 @@ import (
"github.com/dapr/kit/retry"
)
// HandlerResponseItem represents a response from the handler for each message.
type HandlerResponseItem struct {
EntryId string //nolint:stylecheck
Error error
}
// HandlerFunc is the type for handlers that receive messages
type HandlerFunc func(ctx context.Context, msg *azservicebus.ReceivedMessage) error
type HandlerFunc func(ctx context.Context, msgs []*azservicebus.ReceivedMessage) ([]HandlerResponseItem, error)
// Subscription is an object that manages a subscription to an Azure Service Bus receiver, for a topic or queue.
type Subscription struct {
entity string
mu sync.RWMutex
activeMessages map[int64]*azservicebus.ReceivedMessage
activeMessagesChan chan struct{}
receiver *azservicebus.Receiver
timeout time.Duration
retriableErrLimit ratelimit.Limiter
handleChan chan struct{}
logger logger.Logger
ctx context.Context
cancel context.CancelFunc
entity string
mu sync.RWMutex
activeMessages map[int64]*azservicebus.ReceivedMessage
activeOperationsChan chan struct{}
receiver *azservicebus.Receiver
timeout time.Duration
maxBulkSubCount int
retriableErrLimit ratelimit.Limiter
handleChan chan struct{}
logger logger.Logger
ctx context.Context
cancel context.CancelFunc
}
// NewSubscription returns a new Subscription object.
@ -58,13 +65,14 @@ func NewSubscription(
) *Subscription {
ctx, cancel := context.WithCancel(parentCtx)
s := &Subscription{
entity: entity,
activeMessages: make(map[int64]*azservicebus.ReceivedMessage),
activeMessagesChan: make(chan struct{}, maxActiveMessages),
timeout: time.Duration(timeoutInSec) * time.Second,
logger: logger,
ctx: ctx,
cancel: cancel,
entity: entity,
activeMessages: make(map[int64]*azservicebus.ReceivedMessage),
activeOperationsChan: make(chan struct{}, maxActiveMessages), // In case of a non-bulk subscription, one operation is one message.
timeout: time.Duration(timeoutInSec) * time.Second,
maxBulkSubCount: 1, // for non-bulk subscriptions, we only get one message at a time
logger: logger,
ctx: ctx,
cancel: cancel,
}
if maxRetriableEPS > 0 {
@ -81,6 +89,56 @@ func NewSubscription(
return s
}
// NewBulkSubscription returns a new Subscription object with bulk support.
// Parameter "entity" is usually in the format "topic <topicname>" or "queue <queuename>" and it's only used for logging.
func NewBulkSubscription(
parentCtx context.Context,
maxActiveMessages int,
timeoutInSec int,
maxBulkSubCount int,
maxRetriableEPS int,
maxConcurrentHandlers *int,
entity string,
logger logger.Logger,
) *Subscription {
ctx, cancel := context.WithCancel(parentCtx)
s := &Subscription{
entity: entity,
activeMessages: make(map[int64]*azservicebus.ReceivedMessage),
timeout: time.Duration(timeoutInSec) * time.Second,
maxBulkSubCount: maxBulkSubCount,
logger: logger,
ctx: ctx,
cancel: cancel,
}
if maxRetriableEPS > 0 {
s.retriableErrLimit = ratelimit.New(maxRetriableEPS)
} else {
s.retriableErrLimit = ratelimit.NewUnlimited()
}
if maxBulkSubCount < 1 {
s.logger.Warnf("maxBulkSubCount must be greater than 0, setting it to 1")
s.maxBulkSubCount = 1
}
if maxBulkSubCount > maxActiveMessages {
s.logger.Warnf("maxBulkSubCount must not be greater than maxActiveMessages, setting it to %d", maxActiveMessages)
s.maxBulkSubCount = maxActiveMessages
}
// This is a pessimistic estimate of the number of total operations that can be active at any given time.
s.activeOperationsChan = make(chan struct{}, maxActiveMessages/s.maxBulkSubCount)
if maxConcurrentHandlers != nil {
s.logger.Debugf("Subscription to %s is limited to %d message handler(s)", entity, *maxConcurrentHandlers)
s.handleChan = make(chan struct{}, *maxConcurrentHandlers)
}
return s
}
// Connect to a Service Bus topic or queue, blocking until it succeeds; it can retry forever (until the context is canceled).
func (s *Subscription) Connect(newReceiverFunc func() (*azservicebus.Receiver, error)) error {
// Connections need to retry forever with a maximum backoff of 5 minutes and exponential scaling.
@ -112,7 +170,7 @@ func (s *Subscription) Connect(newReceiverFunc func() (*azservicebus.Receiver, e
}
// ReceiveAndBlock is a blocking call to receive messages on an Azure Service Bus subscription from a topic or queue.
func (s *Subscription) ReceiveAndBlock(handler HandlerFunc, lockRenewalInSec int, onFirstSuccess func()) error {
func (s *Subscription) ReceiveAndBlock(handler HandlerFunc, lockRenewalInSec int, bulkEnabled bool, onFirstSuccess func()) error {
ctx, cancel := context.WithCancel(s.ctx)
defer cancel()
@ -141,8 +199,8 @@ func (s *Subscription) ReceiveAndBlock(handler HandlerFunc, lockRenewalInSec int
select {
case s.activeMessagesChan <- struct{}{}:
// No-op
// This blocks if there are too many active messages already
// This is released by the handler, but if the loop ends before it reaches the handler, make sure to release it with `<-s.activeMessagesChan`
// This blocks if there are too many active operations already
// This is released by the handler, but if the loop ends before it reaches the handler, make sure to release it with `<-s.activeOperationsChan`
case <-ctx.Done():
// Return if context is canceled
s.logger.Debugf("Receive context for %s done", s.entity)
@ -150,12 +208,12 @@ func (s *Subscription) ReceiveAndBlock(handler HandlerFunc, lockRenewalInSec int
}
// This method blocks until we get a message or the context is canceled
msgs, err := s.receiver.ReceiveMessages(s.ctx, 1, nil)
msgs, err := s.receiver.ReceiveMessages(s.ctx, s.maxBulkSubCount, nil)
if err != nil {
if err != context.Canceled {
s.logger.Errorf("Error reading from %s. %s", s.entity, err.Error())
}
<-s.activeMessagesChan
<-s.activeOperationsChan
// Return the error. This will cause the Service Bus component to try and reconnect.
return err
}
@ -164,7 +222,7 @@ func (s *Subscription) ReceiveAndBlock(handler HandlerFunc, lockRenewalInSec int
if l == 0 {
// We got no message, which is unusual too
s.logger.Warn("Received 0 messages from Service Bus")
<-s.activeMessagesChan
<-s.activeOperationsChan
// Return an error to force the Service Bus component to try and reconnect.
return errors.New("received 0 messages from Service Bus")
} else if l > 1 {
@ -178,21 +236,83 @@ func (s *Subscription) ReceiveAndBlock(handler HandlerFunc, lockRenewalInSec int
onFirstSuccess = nil
}
msg := msgs[0]
s.logger.Debugf("Received message: %s; current active message usage: %d/%d", msg.MessageID, len(s.activeMessagesChan), cap(s.activeMessagesChan))
// s.logger.Debugf("Message body: %s", string(msg.Body))
s.logger.Debugf("Received messages: %d; current active operations usage: %d/%d", l, len(s.activeOperationsChan), cap(s.activeOperationsChan))
if err = s.addActiveMessage(msg); err != nil {
// If we cannot add the message then sequence number is not set, this must
// be a bug in the Azure Service Bus SDK so we will log the error and not
// handle the message. The message will eventually be retried until fixed.
s.logger.Errorf("Error adding message: %s", err.Error())
<-s.activeMessagesChan
skipProcessing := false
for _, msg := range msgs {
if err = s.addActiveMessage(msg); err != nil {
// If we cannot add the message then sequence number is not set, this must
// be a bug in the Azure Service Bus SDK so we will log the error and not
// handle the message. The message will eventually be retried until fixed.
s.logger.Errorf("Error adding message: %s", err.Error())
skipProcessing = true
break
}
s.logger.Debugf("Processing received message: %s", msg.MessageID)
}
if skipProcessing {
<-s.activeOperationsChan
continue
}
s.logger.Debugf("Processing received message: %s", msg.MessageID)
s.handleAsync(s.ctx, msg, handler)
runHandlerFn := func(hctx context.Context) {
msg := msgs[0]
// Invoke the handler to process the message
_, err = handler(hctx, msgs)
// This context is used for the calls to service bus to finalize (i.e. complete/abandon) the message.
// If we fail to finalize the message, this message will eventually be reprocessed (at-least once delivery).
// This uses a background context in case ctx has been canceled already.
finalizeCtx, finalizeCancel := context.WithTimeout(context.Background(), s.timeout)
defer finalizeCancel()
if err != nil {
// Log the error only, as we're running asynchronously
s.logger.Errorf("App handler returned an error for message %s on %s: %s", msg.MessageID, s.entity, err)
s.AbandonMessage(finalizeCtx, msg)
return
}
s.CompleteMessage(finalizeCtx, msg)
}
bulkRunHandlerFunc := func(hctx context.Context) {
resps, err := handler(hctx, msgs)
// This context is used for the calls to service bus to finalize (i.e. complete/abandon) the message.
// If we fail to finalize the message, this message will eventually be reprocessed (at-least once delivery).
// This uses a background context in case ctx has been canceled already.
finalizeCtx, finalizeCancel := context.WithTimeout(context.Background(), s.timeout)
defer finalizeCancel()
if err != nil {
// Handle the error and mark messages accordingly.
// Note, the order of the responses match the order of the messages.
for i, resp := range resps {
if resp.Error != nil {
// Log the error only, as we're running asynchronously.
s.logger.Errorf("App handler returned an error for message %s on %s: %s", msgs[i].MessageID, s.entity, resp.Error)
s.AbandonMessage(finalizeCtx, msgs[i])
} else {
s.CompleteMessage(finalizeCtx, msgs[i])
}
}
return
}
// No error, so we can complete all messages.
for _, msg := range msgs {
s.CompleteMessage(finalizeCtx, msg)
}
}
if bulkEnabled {
s.handleAsync(s.ctx, msgs, bulkRunHandlerFunc)
} else {
s.handleAsync(s.ctx, msgs, runHandlerFn)
}
}
}
@ -207,69 +327,60 @@ func (s *Subscription) Close(closeCtx context.Context) {
s.cancel()
}
func (s *Subscription) handleAsync(ctx context.Context, msg *azservicebus.ReceivedMessage, handler HandlerFunc) {
// handleAsync handles messages from azure service bus asynchronously.
// runHandlerFn is responsible for calling the message handler function
// and marking messages as complete/abandon.
func (s *Subscription) handleAsync(ctx context.Context, msgs []*azservicebus.ReceivedMessage, runHandlerFn func(ctx context.Context)) {
go func() {
var (
consumeToken bool
takenConcurrentHandler bool
err error
)
defer func() {
// Release a handler if needed
if takenConcurrentHandler {
<-s.handleChan
s.logger.Debugf("Released message handle for %s on %s", msg.MessageID, s.entity)
for _, msg := range msgs {
// Release a handler if needed
if takenConcurrentHandler {
<-s.handleChan
s.logger.Debugf("Released message handle for %s on %s", msg.MessageID, s.entity)
}
// If we got a retriable error (app handler returned a retriable error, or a network error while connecting to the app, etc) consume a retriable error token
// We do it here, after the handler has been released but before removing the active message (which would allow us to retrieve more messages)
if consumeToken {
s.logger.Debugf("Taking a retriable error token")
before := time.Now()
_ = s.retriableErrLimit.Take()
s.logger.Debugf("Resumed after pausing for %v", time.Since(before))
}
// Remove the message from the map of active ones
s.removeActiveMessage(msg.MessageID, *msg.SequenceNumber)
}
// If we got a retriable error (app handler returned a retriable error, or a network error while connecting to the app, etc) consume a retriable error token
// We do it here, after the handler has been released but before removing the active message (which would allow us to retrieve more messages)
if consumeToken {
s.logger.Debugf("Taking a retriable error token")
before := time.Now()
_ = s.retriableErrLimit.Take()
s.logger.Debugf("Resumed after pausing for %v", time.Now().Sub(before))
}
// Remove the message from the map of active ones
s.removeActiveMessage(msg.MessageID, *msg.SequenceNumber)
// Remove an entry from activeMessageChan to allow processing more messages
<-s.activeMessagesChan
// Remove an entry from activeOperationsChan to allow processing more messages
<-s.activeOperationsChan
}()
// If handleChan is non-nil, we have a limit on how many handler we can process
if cap(s.handleChan) > 0 {
s.logger.Debugf("Taking message handle for %s on %s", msg.MessageID, s.entity)
select {
// Context is done, so we will stop waiting
case <-ctx.Done():
s.logger.Debugf("Message context done for %s on %s", msg.MessageID, s.entity)
return
// Blocks until we have a handler available
case s.handleChan <- struct{}{}:
takenConcurrentHandler = true
s.logger.Debugf("Taken message handle for %s on %s", msg.MessageID, s.entity)
for _, msg := range msgs {
// If handleChan is non-nil, we have a limit on how many handler we can process
if cap(s.handleChan) > 0 {
s.logger.Debugf("Taking message handle for %s on %s", msg.MessageID, s.entity)
select {
// Context is done, so we will stop waiting
case <-ctx.Done():
s.logger.Debugf("Message context done for %s on %s", msg.MessageID, s.entity)
return
// Blocks until we have a handler available
case s.handleChan <- struct{}{}:
takenConcurrentHandler = true
s.logger.Debugf("Taken message handle for %s on %s", msg.MessageID, s.entity)
}
}
}
// Invoke the handler to process the message
err = handler(ctx, msg)
// This context is used for the calls to service bus to finalize (i.e. complete/abandon) the message.
// If we fail to finalize the message, this message will eventually be reprocessed (at-least once delivery).
// This uses a background context in case ctx has been canceled already.
finalizeCtx, finalizeCancel := context.WithTimeout(context.Background(), s.timeout)
defer finalizeCancel()
if err != nil {
// Log the error only, as we're running asynchronously
s.logger.Errorf("App handler returned an error for message %s on %s: %s", msg.MessageID, s.entity, err)
s.AbandonMessage(finalizeCtx, msg)
return
}
s.CompleteMessage(finalizeCtx, msg)
// Invoke the handler to process the message.
runHandlerFn(ctx)
}()
}

View File

@ -0,0 +1,63 @@
/*
Copyright 2022 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package servicebus
import (
"context"
"testing"
"github.com/dapr/kit/logger"
)
var maxConcurrentHandlers = 100
func TestNewBulkSubscription_MaxBulkSubCountShouldBeGreaterThanZero(t *testing.T) {
testcases := []struct {
name string
maxBulkSubCountParam int
maxBulkSubCountExpected int
}{
{
"maxBulkSubCount passed is 0",
0,
1,
},
{
"maxBulkSubCount passed is negative",
-100,
1,
},
{
"maxBulkSubCount passed is positive",
100,
100,
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
bulkSubscription := NewBulkSubscription(
context.Background(),
1000,
1,
tc.maxBulkSubCountParam,
10,
&maxConcurrentHandlers,
"test",
logger.NewLogger("test"))
if bulkSubscription.maxBulkSubCount != tc.maxBulkSubCountExpected {
t.Errorf("Expected maxBulkSubCount to be %d but got %d", tc.maxBulkSubCountExpected, bulkSubscription.maxBulkSubCount)
}
})
}
}

View File

@ -17,6 +17,7 @@ import (
"context"
"errors"
"fmt"
"strconv"
"sync"
"time"
@ -31,65 +32,167 @@ type consumer struct {
ready chan bool
running chan struct{}
once sync.Once
mutex sync.Mutex
}
func (consumer *consumer) ConsumeClaim(session sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error {
b := consumer.k.backOffConfig.NewBackOffWithContext(session.Context())
isBulkSubscribe := consumer.k.checkBulkSubscribe(claim.Topic())
for {
select {
case message, ok := <-claim.Messages():
if !ok {
handlerConfig, err := consumer.k.GetTopicHandlerConfig(claim.Topic())
if err != nil {
return fmt.Errorf("error getting bulk handler config for topic %s: %w", claim.Topic(), err)
}
if isBulkSubscribe {
ticker := time.NewTicker(time.Duration(handlerConfig.SubscribeConfig.MaxBulkSubAwaitDurationMs) * time.Millisecond)
defer ticker.Stop()
messages := make([]*sarama.ConsumerMessage, 0, handlerConfig.SubscribeConfig.MaxBulkSubCount)
for {
select {
case <-session.Context().Done():
return consumer.flushBulkMessages(claim, messages, session, handlerConfig.BulkHandler, b)
case message := <-claim.Messages():
consumer.mutex.Lock()
if message != nil {
messages = append(messages, message)
if len(messages) >= handlerConfig.SubscribeConfig.MaxBulkSubCount {
consumer.flushBulkMessages(claim, messages, session, handlerConfig.BulkHandler, b)
messages = messages[:0]
}
}
consumer.mutex.Unlock()
case <-ticker.C:
consumer.mutex.Lock()
consumer.flushBulkMessages(claim, messages, session, handlerConfig.BulkHandler, b)
messages = messages[:0]
consumer.mutex.Unlock()
}
}
} else {
for {
select {
case message, ok := <-claim.Messages():
if !ok {
return nil
}
if consumer.k.consumeRetryEnabled {
if err := retry.NotifyRecover(func() error {
return consumer.doCallback(session, message)
}, b, func(err error, d time.Duration) {
consumer.k.logger.Warnf("Error processing Kafka message: %s/%d/%d [key=%s]. Error: %v. Retrying...", message.Topic, message.Partition, message.Offset, asBase64String(message.Key), err)
}, func() {
consumer.k.logger.Infof("Successfully processed Kafka message after it previously failed: %s/%d/%d [key=%s]", message.Topic, message.Partition, message.Offset, asBase64String(message.Key))
}); err != nil {
consumer.k.logger.Errorf("Too many failed attempts at processing Kafka message: %s/%d/%d [key=%s]. Error: %v.", message.Topic, message.Partition, message.Offset, asBase64String(message.Key), err)
}
} else {
err := consumer.doCallback(session, message)
if err != nil {
consumer.k.logger.Errorf("Error processing Kafka message: %s/%d/%d [key=%s]. Error: %v.", message.Topic, message.Partition, message.Offset, asBase64String(message.Key), err)
}
}
// Should return when `session.Context()` is done.
// If not, will raise `ErrRebalanceInProgress` or `read tcp <ip>:<port>: i/o timeout` when kafka rebalance. see:
// https://github.com/Shopify/sarama/issues/1192
case <-session.Context().Done():
return nil
}
if consumer.k.consumeRetryEnabled {
if err := retry.NotifyRecover(func() error {
return consumer.doCallback(session, message)
}, b, func(err error, d time.Duration) {
consumer.k.logger.Errorf("Error processing Kafka message: %s/%d/%d [key=%s]. Error: %v. Retrying...", message.Topic, message.Partition, message.Offset, asBase64String(message.Key), err)
}, func() {
consumer.k.logger.Infof("Successfully processed Kafka message after it previously failed: %s/%d/%d [key=%s]", message.Topic, message.Partition, message.Offset, asBase64String(message.Key))
}); err != nil {
consumer.k.logger.Errorf("Too many failed attempts at processing Kafka message: %s/%d/%d [key=%s]. Error: %v.", message.Topic, message.Partition, message.Offset, asBase64String(message.Key), err)
}
} else {
err := consumer.doCallback(session, message)
if err != nil {
consumer.k.logger.Errorf("Error processing Kafka message: %s/%d/%d [key=%s]. Error: %v.", message.Topic, message.Partition, message.Offset, asBase64String(message.Key), err)
}
}
// Should return when `session.Context()` is done.
// If not, will raise `ErrRebalanceInProgress` or `read tcp <ip>:<port>: i/o timeout` when kafka rebalance. see:
// https://github.com/Shopify/sarama/issues/1192
case <-session.Context().Done():
return nil
}
}
}
func (consumer *consumer) flushBulkMessages(claim sarama.ConsumerGroupClaim,
messages []*sarama.ConsumerMessage, session sarama.ConsumerGroupSession,
handler BulkEventHandler, b backoff.BackOff,
) error {
if len(messages) > 0 {
if consumer.k.consumeRetryEnabled {
if err := retry.NotifyRecover(func() error {
return consumer.doBulkCallback(session, messages, handler, claim.Topic())
}, b, func(err error, d time.Duration) {
consumer.k.logger.Warnf("Error processing Kafka bulk messages: %s. Error: %v. Retrying...", claim.Topic(), err)
}, func() {
consumer.k.logger.Infof("Successfully processed Kafka message after it previously failed: %s", claim.Topic())
}); err != nil {
consumer.k.logger.Errorf("Too many failed attempts at processing Kafka message: %s. Error: %v.", claim.Topic(), err)
}
} else {
err := consumer.doBulkCallback(session, messages, handler, claim.Topic())
if err != nil {
consumer.k.logger.Errorf("Error processing Kafka message: %s. Error: %v.", claim.Topic(), err)
}
return err
}
}
return nil
}
func (consumer *consumer) doBulkCallback(session sarama.ConsumerGroupSession,
messages []*sarama.ConsumerMessage, handler BulkEventHandler, topic string,
) error {
consumer.k.logger.Debugf("Processing Kafka bulk message: %s", topic)
messageValues := make([]KafkaBulkMessageEntry, (len(messages)))
for i, message := range messages {
if message != nil {
metadata := make(map[string]string, len(message.Headers))
if message.Headers != nil {
for _, t := range message.Headers {
metadata[string(t.Key)] = string(t.Value)
}
}
childMessage := KafkaBulkMessageEntry{
EntryId: strconv.Itoa(i),
Event: message.Value,
Metadata: metadata,
}
messageValues[i] = childMessage
}
}
event := KafkaBulkMessage{
Topic: topic,
Entries: messageValues,
}
responses, err := handler(session.Context(), &event)
if err != nil {
for i, resp := range responses {
// An extra check to confirm that runtime returned responses are in order
if resp.EntryId != messageValues[i].EntryId {
return errors.New("entry id mismatch while processing bulk messages")
}
if resp.Error != nil {
break
}
session.MarkMessage(messages[i], "")
}
} else {
for _, message := range messages {
session.MarkMessage(message, "")
}
}
return err
}
func (consumer *consumer) doCallback(session sarama.ConsumerGroupSession, message *sarama.ConsumerMessage) error {
consumer.k.logger.Debugf("Processing Kafka message: %s/%d/%d [key=%s]", message.Topic, message.Partition, message.Offset, asBase64String(message.Key))
handler, err := consumer.k.GetTopicHandler(message.Topic)
handlerConfig, err := consumer.k.GetTopicHandlerConfig(message.Topic)
if err != nil {
return err
}
if !handlerConfig.IsBulkSubscribe && handlerConfig.Handler == nil {
return errors.New("invalid handler config for subscribe call")
}
event := NewEvent{
Topic: message.Topic,
Data: message.Value,
}
// This is true only when headers are set (Kafka > 0.11)
if message.Headers != nil && len(message.Headers) > 0 {
event.Metadata = make(map[string]string, len(message.Headers))
for _, header := range message.Headers {
event.Metadata[string(header.Key)] = string(header.Value)
}
}
err = handler(session.Context(), &event)
err = handlerConfig.Handler(session.Context(), &event)
if err == nil {
session.MarkMessage(message, "")
}
return err
}
@ -105,10 +208,10 @@ func (consumer *consumer) Setup(sarama.ConsumerGroupSession) error {
return nil
}
// AddTopicHandler adds a topic handler
func (k *Kafka) AddTopicHandler(topic string, handler EventHandler) {
// AddTopicHandler adds a handler and configuration for a topic
func (k *Kafka) AddTopicHandler(topic string, handlerConfig SubscriptionHandlerConfig) {
k.subscribeLock.Lock()
k.subscribeTopics[topic] = handler
k.subscribeTopics[topic] = handlerConfig
k.subscribeLock.Unlock()
}
@ -119,14 +222,26 @@ func (k *Kafka) RemoveTopicHandler(topic string) {
k.subscribeLock.Unlock()
}
// GetTopicHandler returns the handler for a topic
func (k *Kafka) GetTopicHandler(topic string) (EventHandler, error) {
handler, ok := k.subscribeTopics[topic]
if !ok || handler == nil {
return nil, fmt.Errorf("handler for messages of topic %s not found", topic)
// checkBulkSubscribe checks if a bulk handler and config are correctly registered for provided topic
func (k *Kafka) checkBulkSubscribe(topic string) bool {
if bulkHandlerConfig, ok := k.subscribeTopics[topic]; ok &&
bulkHandlerConfig.IsBulkSubscribe &&
bulkHandlerConfig.BulkHandler != nil && (bulkHandlerConfig.SubscribeConfig.MaxBulkSubCount > 0) &&
bulkHandlerConfig.SubscribeConfig.MaxBulkSubAwaitDurationMs > 0 {
return true
}
return false
}
return handler, nil
// GetTopicBulkHandler returns the handlerConfig for a topic
func (k *Kafka) GetTopicHandlerConfig(topic string) (SubscriptionHandlerConfig, error) {
handlerConfig, ok := k.subscribeTopics[topic]
if ok && ((handlerConfig.IsBulkSubscribe && handlerConfig.BulkHandler != nil) ||
(!handlerConfig.IsBulkSubscribe && handlerConfig.Handler != nil)) {
return handlerConfig, nil
}
return SubscriptionHandlerConfig{},
fmt.Errorf("any handler for messages of topic %s not found", topic)
}
// Subscribe to topic in the Kafka cluster, in a background goroutine

View File

@ -20,6 +20,7 @@ import (
"github.com/Shopify/sarama"
"github.com/dapr/components-contrib/pubsub"
"github.com/dapr/kit/logger"
"github.com/dapr/kit/retry"
)
@ -38,7 +39,7 @@ type Kafka struct {
cancel context.CancelFunc
consumer consumer
config *sarama.Config
subscribeTopics TopicHandlers
subscribeTopics TopicHandlerConfig
subscribeLock sync.Mutex
backOffConfig retry.Config
@ -53,7 +54,7 @@ type Kafka struct {
func NewKafka(logger logger.Logger) *Kafka {
return &Kafka{
logger: logger,
subscribeTopics: make(TopicHandlers),
subscribeTopics: make(TopicHandlerConfig),
subscribeLock: sync.Mutex{},
}
}
@ -146,6 +147,17 @@ func (k *Kafka) Close() (err error) {
// EventHandler is the handler used to handle the subscribed event.
type EventHandler func(ctx context.Context, msg *NewEvent) error
// BulkEventHandler is the handler used to handle the subscribed bulk event.
type BulkEventHandler func(ctx context.Context, msg *KafkaBulkMessage) ([]pubsub.BulkSubscribeResponseEntry, error)
// SubscriptionHandlerConfig is the handler and configuration for subscription.
type SubscriptionHandlerConfig struct {
IsBulkSubscribe bool
SubscribeConfig pubsub.BulkSubscribeConfig
BulkHandler BulkEventHandler
Handler EventHandler
}
// NewEvent is an event arriving from a message bus instance.
type NewEvent struct {
Data []byte `json:"data"`
@ -153,3 +165,18 @@ type NewEvent struct {
Metadata map[string]string `json:"metadata"`
ContentType *string `json:"contentType,omitempty"`
}
// KafkaBulkMessage is a bulk event arriving from a message bus instance.
type KafkaBulkMessage struct {
Entries []KafkaBulkMessageEntry `json:"entries"`
Topic string `json:"topic"`
Metadata map[string]string `json:"metadata"`
}
// KafkaBulkMessageEntry is an item contained inside bulk event arriving from a message bus instance.
type KafkaBulkMessageEntry struct {
EntryId string `json:"entryId"` //nolint:stylecheck
Event []byte `json:"event"`
ContentType string `json:"contentType,omitempty"`
Metadata map[string]string `json:"metadata"`
}

View File

@ -14,9 +14,12 @@ limitations under the License.
package kafka
import (
"context"
"errors"
"github.com/Shopify/sarama"
"github.com/dapr/components-contrib/pubsub"
)
func getSyncProducer(config sarama.Config, brokers []string, maxMessageBytes int) (sarama.SyncProducer, error) {
@ -74,3 +77,96 @@ func (k *Kafka) Publish(topic string, data []byte, metadata map[string]string) e
return nil
}
func (k *Kafka) BulkPublish(_ context.Context, topic string, entries []pubsub.BulkMessageEntry, metadata map[string]string) (pubsub.BulkPublishResponse, error) {
if k.producer == nil {
err := errors.New("component is closed")
return pubsub.NewBulkPublishResponse(entries, pubsub.PublishFailed, err), err
}
k.logger.Debugf("Bulk Publishing on topic %v", topic)
msgs := []*sarama.ProducerMessage{}
for _, entry := range entries {
msg := &sarama.ProducerMessage{
Topic: topic,
Value: sarama.ByteEncoder(entry.Event),
}
// From Sarama documentation
// This field is used to hold arbitrary data you wish to include so it
// will be available when receiving on the Successes and Errors channels.
// Sarama completely ignores this field and is only to be used for
// pass-through data.
// This pass thorugh field is used for mapping errors, as seen in the mapKafkaProducerErrors method
// The EntryId will be unique for this request and the ProducerMessage is returned on the Errros channel,
// the metadata in that field is compared to the entry metadata to generate the right response on partial failures
msg.Metadata = entry.EntryId
for name, value := range metadata {
if name == key {
msg.Key = sarama.StringEncoder(value)
} else {
if msg.Headers == nil {
msg.Headers = make([]sarama.RecordHeader, 0, len(metadata))
}
msg.Headers = append(msg.Headers, sarama.RecordHeader{
Key: []byte(name),
Value: []byte(value),
})
}
}
msgs = append(msgs, msg)
}
if err := k.producer.SendMessages(msgs); err != nil {
// map the returned error to different entries
return k.mapKafkaProducerErrors(err, entries), err
}
return pubsub.NewBulkPublishResponse(entries, pubsub.PublishSucceeded, nil), nil
}
// mapKafkaProducerErrors to correct response statuses
func (k *Kafka) mapKafkaProducerErrors(err error, entries []pubsub.BulkMessageEntry) pubsub.BulkPublishResponse {
var pErrs sarama.ProducerErrors
if !errors.As(err, &pErrs) {
// Ideally this condition should not be executed, but in the scenario that the err is not of sarama.ProducerErrors type
// return a default error that all messages have failed
return pubsub.NewBulkPublishResponse(entries, pubsub.PublishFailed, err)
}
resp := pubsub.BulkPublishResponse{
Statuses: make([]pubsub.BulkPublishResponseEntry, 0, len(entries)),
}
// used in the case of the partial success scenario
alreadySeen := map[string]struct{}{}
for _, pErr := range pErrs {
if entryId, ok := pErr.Msg.Metadata.(string); ok { //nolint:stylecheck
alreadySeen[entryId] = struct{}{}
resp.Statuses = append(resp.Statuses, pubsub.BulkPublishResponseEntry{
Status: pubsub.PublishFailed,
EntryId: entryId,
Error: pErr.Err,
})
} else {
// Ideally this condition should not be executed, but in the scenario that the Metadata field
// is not of string type return a default error that all messages have failed
k.logger.Warnf("error parsing bulk errors from Kafka, returning default error response of all failed")
return pubsub.NewBulkPublishResponse(entries, pubsub.PublishFailed, err)
}
}
// Check if all the messages have failed
if len(pErrs) != len(entries) {
// This is a partial success scenario
for _, entry := range entries {
// Check if the entryId was not seen in the pErrs list
if _, ok := alreadySeen[entry.EntryId]; !ok {
// this is a message that has succeeded
resp.Statuses = append(resp.Statuses, pubsub.BulkPublishResponseEntry{
Status: pubsub.PublishSucceeded,
EntryId: entry.EntryId,
})
}
}
}
return resp
}

View File

@ -17,11 +17,21 @@ import (
"encoding/base64"
"encoding/pem"
"fmt"
"strconv"
"strings"
"github.com/Shopify/sarama"
)
const (
// DefaultMaxBulkSubCount is the default max bulk count for kafka pubsub component
// if the MaxBulkCountKey is not set in the metadata.
DefaultMaxBulkSubCount = 80
// DefaultMaxBulkSubAwaitDurationMs is the default max bulk await duration for kafka pubsub component
// if the MaxBulkAwaitDurationKey is not set in the metadata.
DefaultMaxBulkSubAwaitDurationMs = 10000
)
// asBase64String implements the `fmt.Stringer` interface in order to print
// `[]byte` as a base 64 encoded string.
// It is used above to log the message key. The call to `EncodeToString`
@ -52,16 +62,27 @@ func isValidPEM(val string) bool {
return block != nil
}
// Map of topics and their handlers
type TopicHandlers map[string]EventHandler
// TopicHandlerConfig is the map of topics and sruct containing handler and their config.
type TopicHandlerConfig map[string]SubscriptionHandlerConfig
// TopicList returns the list of topics
func (th TopicHandlers) TopicList() []string {
topics := make([]string, len(th))
// // TopicList returns the list of topics
func (tbh TopicHandlerConfig) TopicList() []string {
topics := make([]string, len(tbh))
i := 0
for topic := range th {
for topic := range tbh {
topics[i] = topic
i++
}
return topics
}
// GetIntFromMetadata returns an int value from metadata OR default value if key not found or if its
// value not convertible to int.
func GetIntFromMetadata(metadata map[string]string, key string, defaultValue int) int {
if val, ok := metadata[key]; ok {
if intVal, err := strconv.Atoi(val); err == nil {
return intVal
}
}
return defaultValue
}

View File

@ -0,0 +1,34 @@
package httputils
import (
"net/http"
"net/url"
)
// RequestURI returns the path and query string (if present) from the request
// For example: `/foo` or `/foo?hello=world`
func RequestURI(r *http.Request) string {
u := r.URL
result := u.EscapedPath()
if result == "" {
result = "/"
}
if u.ForceQuery || u.RawQuery != "" {
result += "?" + u.RawQuery
}
return result
}
// SetRequestURI replaces the path and query string (if present) from the
// request with the input. For example: `/foo` or `/foo?hello=world`
func SetRequestURI(r *http.Request, uri string) error {
if u, err := url.ParseRequestURI(uri); err != nil {
return err
} else { // copy the URI without overwriting the host, etc.
r.URL.RawPath = u.RawPath
r.URL.Path = u.Path
r.URL.ForceQuery = u.ForceQuery
r.URL.RawQuery = u.RawQuery
}
return nil
}

View File

@ -0,0 +1,114 @@
package httputils
import (
"net/http"
"net/url"
"testing"
)
func TestRequestURI(t *testing.T) {
tests := []struct {
name string
url *url.URL
expectedURI string
}{
{
name: "coerces empty path to slash",
url: &url.URL{
Scheme: "http",
Host: "example.com",
Path: "",
},
expectedURI: "/",
},
{
name: "encodes space",
url: &url.URL{
Scheme: "http",
Host: "example.com",
Path: "/a b",
},
expectedURI: "/a%20b",
},
{
name: "encodes query",
url: &url.URL{
Scheme: "http",
Host: "example.com",
Path: "/a b",
RawQuery: "q=go+language",
},
expectedURI: "/a%20b?q=go+language",
},
{
name: "double slash path",
url: &url.URL{
Scheme: "http",
Host: "example.com",
Path: "//foo",
},
expectedURI: "//foo",
},
{
name: "empty query",
url: &url.URL{
Scheme: "http",
Host: "example.com",
Path: "/foo",
ForceQuery: true,
},
expectedURI: "/foo?",
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
r := &http.Request{URL: tc.url}
if want, have := tc.expectedURI, RequestURI(r); want != have {
t.Errorf("unexpected uri, want: %s, have: %s", want, have)
}
})
}
}
func Test_SetRequestURI(t *testing.T) {
tests := []struct {
name string
expectedURI string
}{
{
name: "coerces empty path to slash",
expectedURI: "/",
},
{
name: "encodes space",
expectedURI: "/a%20b",
},
{
name: "encodes query",
expectedURI: "/a%20b?q=go+language",
},
{
name: "double slash path",
expectedURI: "//foo",
},
{
name: "empty query",
expectedURI: "/foo?",
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
r := &http.Request{URL: &url.URL{}}
if err := SetRequestURI(r, tc.expectedURI); err != nil {
t.Error(err)
}
if want, have := tc.expectedURI, r.URL.RequestURI(); want != have {
t.Errorf("unexpected uri, want: %s, have: %s", want, have)
}
})
}
}

View File

@ -0,0 +1,33 @@
package httputils
import (
"net/http"
)
// RespondWithError responds to a http.ResponseWriter with an error status code.
// The text corresponding to the status code is sent as body of the response.
// This method should be invoked before calling w.WriteHeader, and callers should abort the request after calling this method.
func RespondWithError(w http.ResponseWriter, statusCode int) {
statusText := http.StatusText(statusCode)
if statusText == "" {
statusCode = http.StatusInternalServerError
statusText = http.StatusText(statusCode)
}
RespondWithErrorAndMessage(w, statusCode, statusText)
}
// RespondWithErrorAndMessage responds to a http.ResponseWriter with an error status code.
// The message is included in the body as response.
// This method should be invoked before calling w.WriteHeader, and callers should abort the request after calling this method.
func RespondWithErrorAndMessage(w http.ResponseWriter, statusCode int, message string) {
w.Header().Set("content-type", "text/plain; charset=utf-8")
w.WriteHeader(statusCode)
w.Write([]byte(message))
}
// RespondWithRedirect responds to a http.ResponseWriter with a redirect.
// This method should be invoked before calling w.WriteHeader, and callers should abort the request after calling this method.
func RespondWithRedirect(w http.ResponseWriter, statusCode int, location string) {
w.Header().Set("location", location)
w.WriteHeader(statusCode)
}

View File

@ -1,6 +1,20 @@
/*
Copyright 2022 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package utils
import (
"strconv"
"strings"
)
@ -14,3 +28,21 @@ func IsTruthy(val string) bool {
return false
}
}
// GetElemOrDefaultFromMap returns the value of a key from a map, or a default value
// if the key does not exist or the value is not of the expected type.
func GetElemOrDefaultFromMap[T int | uint64](m map[string]string, key string, def T) T {
if val, ok := m[key]; ok {
switch any(def).(type) {
case int:
if ival, err := strconv.ParseInt(val, 10, 64); err == nil {
return T(ival)
}
case uint64:
if uval, err := strconv.ParseUint(val, 10, 64); err == nil {
return T(uval)
}
}
}
return def
}

View File

@ -0,0 +1,98 @@
/*
Copyright 2022 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package utils
import "testing"
func TestGetElemOrDefaultFromMap(t *testing.T) {
t.Run("test int", func(t *testing.T) {
testcases := []struct {
name string
m map[string]string
key string
def int
expected int
}{
{
name: "Get an int value from map that exists",
m: map[string]string{"key": "1"},
key: "key",
def: 0,
expected: 1,
},
{
name: "Get an int value from map that does not exist",
m: map[string]string{"key": "1"},
key: "key2",
def: 0,
expected: 0,
},
{
name: "Get an int value from map that exists but is not an int",
m: map[string]string{"key": "a"},
key: "key",
def: 0,
expected: 0,
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
actual := GetElemOrDefaultFromMap(tc.m, tc.key, tc.def)
if actual != tc.expected {
t.Errorf("expected %v, got %v", tc.expected, actual)
}
})
}
})
t.Run("test uint64", func(t *testing.T) {
testcases := []struct {
name string
m map[string]string
key string
def uint64
expected uint64
}{
{
name: "Get an uint64 value from map that exists",
m: map[string]string{"key": "1"},
key: "key",
def: uint64(0),
expected: uint64(1),
},
{
name: "Get an uint64 value from map that does not exist",
m: map[string]string{"key": "1"},
key: "key2",
def: uint64(0),
expected: uint64(0),
},
{
name: "Get an int value from map that exists but is not an uint64",
m: map[string]string{"key": "-1"},
key: "key",
def: 0,
expected: 0,
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
actual := GetElemOrDefaultFromMap(tc.m, tc.key, tc.def)
if actual != tc.expected {
t.Errorf("expected %v, got %v", tc.expected, actual)
}
})
}
})
}

View File

@ -38,6 +38,15 @@ const (
// QueryIndexName defines the metadata key for the name of query indexing schema (for redis).
QueryIndexName = "queryIndexName"
// MaxBulkCountSubKey defines the maximum number of messages to be sent in a single bulk subscribe request.
MaxBulkSubCountKey string = "maxBulkSubCount"
// MaxBulkAwaitDurationKey is the key for the max bulk await duration in the metadata.
MaxBulkSubAwaitDurationMsKey string = "maxBulkSubAwaitDurationMs"
// MaxBulkPubBytesKey defines the maximum bytes to publish in a bulk publish request metadata.
MaxBulkPubBytesKey string = "maxBulkPubBytes"
)
// TryGetTTL tries to get the ttl as a time.Duration value for pubsub, binding and any other building block.

View File

@ -15,12 +15,13 @@ package bearer
import (
"context"
"encoding/json"
"net/http"
"strings"
oidc "github.com/coreos/go-oidc"
"github.com/valyala/fasthttp"
"github.com/dapr/components-contrib/internal/httputils"
mdutils "github.com/dapr/components-contrib/metadata"
"github.com/dapr/components-contrib/middleware"
"github.com/dapr/kit/logger"
)
@ -31,14 +32,12 @@ type bearerMiddlewareMetadata struct {
}
// NewBearerMiddleware returns a new oAuth2 middleware.
func NewBearerMiddleware(logger logger.Logger) middleware.Middleware {
return &Middleware{logger: logger}
func NewBearerMiddleware(_ logger.Logger) middleware.Middleware {
return &Middleware{}
}
// Middleware is an oAuth2 authentication middleware.
type Middleware struct {
logger logger.Logger
}
type Middleware struct{}
const (
bearerPrefix = "bearer "
@ -46,7 +45,7 @@ const (
)
// GetHandler retruns the HTTP handler provided by the middleware.
func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.RequestHandler) fasthttp.RequestHandler, error) {
func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(next http.Handler) http.Handler, error) {
meta, err := m.getNativeMetadata(metadata)
if err != nil {
return nil, err
@ -61,38 +60,30 @@ func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.R
ClientID: meta.ClientID,
})
return func(h fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
authHeader := string(ctx.Request.Header.Peek(fasthttp.HeaderAuthorization))
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authHeader := r.Header.Get("authorization")
if !strings.HasPrefix(strings.ToLower(authHeader), bearerPrefix) {
ctx.Error(fasthttp.StatusMessage(fasthttp.StatusUnauthorized), fasthttp.StatusUnauthorized)
httputils.RespondWithError(w, http.StatusUnauthorized)
return
}
rawToken := authHeader[bearerPrefixLength:]
_, err := verifier.Verify(ctx, rawToken)
_, err := verifier.Verify(r.Context(), rawToken)
if err != nil {
ctx.Error(fasthttp.StatusMessage(fasthttp.StatusUnauthorized), fasthttp.StatusUnauthorized)
httputils.RespondWithError(w, http.StatusUnauthorized)
return
}
h(ctx)
}
next.ServeHTTP(w, r)
})
}, nil
}
func (m *Middleware) getNativeMetadata(metadata middleware.Metadata) (*bearerMiddlewareMetadata, error) {
b, err := json.Marshal(metadata.Properties)
if err != nil {
return nil, err
}
var middlewareMetadata bearerMiddlewareMetadata
err = json.Unmarshal(b, &middlewareMetadata)
err := mdutils.DecodeMetadata(metadata.Properties, &middlewareMetadata)
if err != nil {
return nil, err
}
return &middlewareMetadata, nil
}

View File

@ -1,84 +0,0 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package nethttpadaptor
import (
"io"
"net"
"net/http"
"strconv"
"github.com/valyala/fasthttp"
"github.com/dapr/kit/logger"
)
// NewNetHTTPHandlerFunc wraps a fasthttp.RequestHandler in a http.HandlerFunc.
func NewNetHTTPHandlerFunc(logger logger.Logger, h fasthttp.RequestHandler) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
c := fasthttp.RequestCtx{}
remoteIP := net.ParseIP(r.RemoteAddr)
remoteAddr := net.IPAddr{remoteIP, ""} //nolint
c.Init(&fasthttp.Request{}, &remoteAddr, nil)
if r.Body != nil {
reqBody, err := io.ReadAll(r.Body)
if err != nil {
logger.Errorf("error reading request body, %+v", err)
return
}
c.Request.SetBody(reqBody)
}
c.Request.SetRequestURI(r.URL.RequestURI())
c.Request.URI().SetScheme(r.URL.Scheme)
c.Request.SetHost(r.Host)
c.Request.Header.SetMethod(r.Method)
c.Request.Header.Set("Proto", r.Proto)
major := strconv.Itoa(r.ProtoMajor)
minor := strconv.Itoa(r.ProtoMinor)
c.Request.Header.Set("Protomajor", major)
c.Request.Header.Set("Protominor", minor)
c.Request.Header.SetContentType(r.Header.Get("Content-Type"))
c.Request.Header.SetContentLength(int(r.ContentLength))
c.Request.Header.SetReferer(r.Referer())
c.Request.Header.SetUserAgent(r.UserAgent())
for _, cookie := range r.Cookies() {
c.Request.Header.SetCookie(cookie.Name, cookie.Value)
}
for k, v := range r.Header {
for _, i := range v {
c.Request.Header.Add(k, i)
}
}
ctx := r.Context()
reqCtx, ok := ctx.(*fasthttp.RequestCtx)
if ok {
reqCtx.VisitUserValues(func(k []byte, v interface{}) {
c.SetUserValueBytes(k, v)
})
}
h(&c)
c.Response.Header.VisitAll(func(k []byte, v []byte) {
w.Header().Add(string(k), string(v))
})
status := c.Response.StatusCode()
w.WriteHeader(status)
c.Response.BodyWriteTo(w)
})
}

View File

@ -1,497 +0,0 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package nethttpadaptor
import (
"context"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/valyala/fasthttp"
"github.com/dapr/kit/logger"
)
func TestNewNetHTTPHandlerFuncRequests(t *testing.T) {
testLogger := logger.NewLogger("test")
tests := []struct {
name string
inputRequestFactory func() *http.Request
evaluateFactory func(t *testing.T) func(ctx *fasthttp.RequestCtx)
}{
{
"Get method is handled",
func() *http.Request {
return httptest.NewRequest(http.MethodGet, "http://localhost:8080/test", nil)
},
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
return func(ctx *fasthttp.RequestCtx) {
assert.Equal(t, http.MethodGet, string(ctx.Method()))
}
},
},
{
"Post method is handled",
func() *http.Request {
return httptest.NewRequest(http.MethodPost, "http://localhost:8080/test", nil)
},
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
return func(ctx *fasthttp.RequestCtx) {
assert.Equal(t, http.MethodPost, string(ctx.Method()))
}
},
},
{
"Put method is handled",
func() *http.Request {
return httptest.NewRequest(http.MethodPut, "http://localhost:8080/test", nil)
},
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
return func(ctx *fasthttp.RequestCtx) {
assert.Equal(t, http.MethodPut, string(ctx.Method()))
}
},
},
{
"Options method is handled",
func() *http.Request {
return httptest.NewRequest(http.MethodOptions, "http://localhost:8080/test", nil)
},
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
return func(ctx *fasthttp.RequestCtx) {
assert.Equal(t, http.MethodOptions, string(ctx.Method()))
}
},
},
{
"Patch method is handled",
func() *http.Request {
return httptest.NewRequest(http.MethodPatch, "http://localhost:8080/test", nil)
},
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
return func(ctx *fasthttp.RequestCtx) {
assert.Equal(t, http.MethodPatch, string(ctx.Method()))
}
},
},
{
"Delete method is handled",
func() *http.Request {
return httptest.NewRequest(http.MethodDelete, "http://localhost:8080/test", nil)
},
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
return func(ctx *fasthttp.RequestCtx) {
assert.Equal(t, http.MethodDelete, string(ctx.Method()))
}
},
},
{
"Host is handled",
func() *http.Request {
return httptest.NewRequest(http.MethodGet, "http://localhost:8080/test", nil)
},
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
return func(ctx *fasthttp.RequestCtx) {
assert.Equal(t, "localhost:8080", string(ctx.Host()))
}
},
},
{
"Path is handled",
func() *http.Request {
return httptest.NewRequest(http.MethodGet, "http://localhost:8080/test/sub", nil)
},
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
return func(ctx *fasthttp.RequestCtx) {
assert.Equal(t, "/test/sub", string(ctx.Path()))
}
},
},
{
"Body is handled",
func() *http.Request {
body := strings.NewReader("test body!")
return httptest.NewRequest(http.MethodGet, "http://localhost:8080/test/sub", body)
},
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
return func(ctx *fasthttp.RequestCtx) {
assert.Equal(t, "test body!", string(ctx.Request.Body()))
}
},
},
{
"Querystring is handled",
func() *http.Request {
return httptest.NewRequest(http.MethodGet, "http://localhost:8080/test/sub?alice=bob&version=0.1.2", nil)
},
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
return func(ctx *fasthttp.RequestCtx) {
assert.Equal(t, "alice=bob&version=0.1.2", string(ctx.Request.URI().QueryString()))
}
},
},
{
"Headers are handled",
func() *http.Request {
req := httptest.NewRequest(http.MethodGet, "http://localhost:8080/test/sub?alice=bob&version=0.1.2", nil)
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) {
return func(ctx *fasthttp.RequestCtx) {
var header1Found bool
var header2Found bool
var header3Found bool
ctx.Request.Header.VisitAll(func(k []byte, v []byte) {
switch string(k) {
case "Testheaderkey1":
header1Found = true
case "Testheaderkey2":
header2Found = true
case "Testheaderkey3":
header3Found = true
}
})
assert.True(t, header1Found, "header1Found should be true but is false")
assert.True(t, header2Found, "header2Found should be true but is false")
assert.True(t, header3Found, "header3Found should be true but is false")
}
},
},
{
"Duplicate headers are handled",
func() *http.Request {
req := httptest.NewRequest(http.MethodGet, "http://localhost:8080/test/sub?alice=bob&version=0.1.2", nil)
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) {
return func(ctx *fasthttp.RequestCtx) {
var headerValue1Found bool
var headerValue2Found bool
var headerValue3Found bool
ctx.Request.Header.VisitAll(func(k []byte, v []byte) {
if string(k) == "Testheaderkey1" {
switch string(v) {
case "testHeaderValue1":
headerValue1Found = true
case "testHeaderValue2":
headerValue2Found = true
case "testHeaderValue3":
headerValue3Found = true
}
}
})
assert.True(t, headerValue1Found, "headerValue1Found should be true but is false")
assert.True(t, headerValue2Found, "headerValue2Found should be true but is false")
assert.True(t, headerValue3Found, "headerValue3Found should be true but is false")
}
},
},
{
"Scheme is handled",
func() *http.Request {
return httptest.NewRequest(http.MethodGet, "https://localhost:8080", nil)
},
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
return func(ctx *fasthttp.RequestCtx) {
assert.Equal(t, "https", string(ctx.Request.URI().Scheme()))
}
},
},
{
"Content-Type is handled",
func() *http.Request {
req := httptest.NewRequest(http.MethodGet, "https://localhost:8080", nil)
req.Header.Add("Content-Type", "application/json")
return req
},
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
return func(ctx *fasthttp.RequestCtx) {
assert.Equal(t, "application/json", string(ctx.Request.Header.ContentType()))
}
},
},
{
"Content-Type with boundary is handled",
func() *http.Request {
req := httptest.NewRequest(http.MethodGet, "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) {
return func(ctx *fasthttp.RequestCtx) {
assert.Equal(t, "multipart/form-data; boundary=test-boundary", string(ctx.Request.Header.ContentType()))
}
},
},
{
"User-Agent is handled",
func() *http.Request {
req := httptest.NewRequest(http.MethodGet, "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) {
return func(ctx *fasthttp.RequestCtx) {
assert.Equal(t, "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", string(ctx.Request.Header.UserAgent()))
}
},
},
{
"Referer is handled",
func() *http.Request {
req := httptest.NewRequest(http.MethodGet, "https://localhost:8080", nil)
req.Header.Add("Referer", "testReferer")
return req
},
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
return func(ctx *fasthttp.RequestCtx) {
assert.Equal(t, "testReferer", string(ctx.Request.Header.Referer()))
}
},
},
{
"BasicAuth is handled",
func() *http.Request {
req := httptest.NewRequest(http.MethodGet, "https://localhost:8080", nil)
req.Header.Add("Authorization", "Basic YWxhZGRpbjpvcGVuc2VzYW1l") // b64(aladdin:opensesame)
return req
},
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
return func(ctx *fasthttp.RequestCtx) {
var basicAuth string
ctx.Request.Header.VisitAll(func(k []byte, v []byte) {
if string(k) == "Authorization" {
basicAuth = string(v)
}
})
assert.Equal(t, "Basic YWxhZGRpbjpvcGVuc2VzYW1l", basicAuth)
}
},
},
{
"RemoteAddr is handled",
func() *http.Request {
req := httptest.NewRequest(http.MethodGet, "https://localhost:8080", nil)
req.RemoteAddr = "1.1.1.1"
return req
},
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
return func(ctx *fasthttp.RequestCtx) {
assert.Equal(t, "1.1.1.1", ctx.RemoteAddr().String())
}
},
},
{
"nil body is handled",
func() *http.Request {
req, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "https://localhost:8080", nil)
return req
},
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
return func(ctx *fasthttp.RequestCtx) {
assert.Equal(t, 0, len(ctx.Request.Body()))
}
},
},
{
"proto headers are handled",
func() *http.Request {
req, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "https://localhost:8080", nil)
return req
},
func(t *testing.T) func(ctx *fasthttp.RequestCtx) {
return func(ctx *fasthttp.RequestCtx) {
var major, minor string
ctx.Request.Header.VisitAll(func(k []byte, v []byte) {
if strings.EqualFold(string(k), "protomajor") {
major = string(v)
}
if strings.EqualFold(string(k), "protominor") {
minor = string(v)
}
})
assert.Equal(t, "1", major)
assert.Equal(t, "1", minor)
}
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := tt.inputRequestFactory()
handler := NewNetHTTPHandlerFunc(testLogger, tt.evaluateFactory(t))
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
})
}
}
func TestNewNetHTTPHandlerFuncResponses(t *testing.T) {
testLogger := logger.NewLogger("test")
tests := []struct {
name string
inputHandlerFactory func() fasthttp.RequestHandler
inputRequestFactory func() *http.Request
evaluate func(t *testing.T, res *http.Response)
}{
{
"200 status code is handled",
func() fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
ctx.SetStatusCode(200)
}
},
func() *http.Request {
return httptest.NewRequest(http.MethodGet, "http://localhost:8080/test", nil)
},
func(t *testing.T, res *http.Response) {
assert.Equal(t, 200, res.StatusCode)
},
},
{
"500 status code is handled",
func() fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
ctx.SetStatusCode(500)
}
},
func() *http.Request {
return httptest.NewRequest(http.MethodGet, "http://localhost:8080/test", nil)
},
func(t *testing.T, res *http.Response) {
assert.Equal(t, 500, res.StatusCode)
},
},
{
"400 status code is handled",
func() fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
ctx.SetStatusCode(400)
}
},
func() *http.Request {
return httptest.NewRequest(http.MethodGet, "http://localhost:8080/test", nil)
},
func(t *testing.T, res *http.Response) {
assert.Equal(t, 400, res.StatusCode)
},
},
{
"Body is handled",
func() fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
ctx.Response.SetBodyString("test body!")
}
},
func() *http.Request {
return httptest.NewRequest(http.MethodGet, "http://localhost:8080/test", nil)
},
func(t *testing.T, res *http.Response) {
body, _ := io.ReadAll(res.Body)
assert.Equal(t, "test body!", string(body))
},
},
{
"Single headers are handled",
func() fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
ctx.Response.Header.SetContentType("application/json")
}
},
func() *http.Request {
return httptest.NewRequest(http.MethodGet, "http://localhost:8080/test", nil)
},
func(t *testing.T, res *http.Response) {
key := res.Header.Get("Content-Type")
assert.Equal(t, "application/json", key)
},
},
{
"Duplicate headers are handled",
func() fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
ctx.Response.Header.Add("X-Transfer-Encoding", "chunked")
ctx.Response.Header.Add("X-Transfer-Encoding", "compress")
ctx.Response.Header.Add("X-Transfer-Encoding", "deflate")
ctx.Response.Header.Add("X-Transfer-Encoding", "gzip")
}
},
func() *http.Request {
return httptest.NewRequest(http.MethodGet, "http://localhost:8080/test", nil)
},
func(t *testing.T, res *http.Response) {
encodings := res.TransferEncoding // TODO: How to set this property?
if encodings == nil {
encodings = res.Header["X-Transfer-Encoding"]
}
var chunked, compress, deflate, gzip bool
for _, encoding := range encodings {
switch encoding {
case "chunked":
chunked = true
case "compress":
compress = true
case "deflate":
deflate = true
case "gzip":
gzip = true
}
}
assert.True(t, chunked, "expected chunked to be true but was false")
assert.True(t, compress, "expected compress to be true but was false")
assert.True(t, deflate, "expected deflate to be true but was false")
assert.True(t, gzip, "expected gzip to be true but was false")
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
handler := tt.inputHandlerFactory()
request := tt.inputRequestFactory()
newNetHTTPHandler := NewNetHTTPHandlerFunc(testLogger, handler)
w := httptest.NewRecorder()
newNetHTTPHandler.ServeHTTP(w, request)
res := w.Result()
defer res.Body.Close()
tt.evaluate(t, res)
})
}
}

View File

@ -14,16 +14,19 @@ limitations under the License.
package oauth2
import (
"context"
"encoding/json"
"net/http"
"net/url"
"strings"
"github.com/fasthttp-contrib/sessions"
"github.com/google/uuid"
"github.com/valyala/fasthttp"
"golang.org/x/oauth2"
"github.com/dapr/components-contrib/internal/httputils"
"github.com/dapr/components-contrib/internal/utils"
mdutils "github.com/dapr/components-contrib/metadata"
"github.com/dapr/components-contrib/middleware"
"github.com/dapr/kit/logger"
)
// Metadata is the oAuth middleware config.
@ -39,100 +42,111 @@ type oAuth2MiddlewareMetadata struct {
}
// NewOAuth2Middleware returns a new oAuth2 middleware.
func NewOAuth2Middleware() middleware.Middleware {
return &Middleware{}
func NewOAuth2Middleware(log logger.Logger) middleware.Middleware {
return &Middleware{logger: log}
}
// Middleware is an oAuth2 authentication middleware.
type Middleware struct{}
type Middleware struct {
logger logger.Logger
}
const (
stateParam = "state"
savedState = "auth-state"
redirectPath = "redirect-url"
codeParam = "code"
https = "https://"
)
// GetHandler retruns the HTTP handler provided by the middleware.
func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.RequestHandler) fasthttp.RequestHandler, error) {
func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(next http.Handler) http.Handler, error) {
meta, err := m.getNativeMetadata(metadata)
if err != nil {
return nil, err
}
return func(h fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
conf := &oauth2.Config{
ClientID: meta.ClientID,
ClientSecret: meta.ClientSecret,
Scopes: strings.Split(meta.Scopes, ","),
RedirectURL: meta.RedirectURL,
Endpoint: oauth2.Endpoint{
AuthURL: meta.AuthURL,
TokenURL: meta.TokenURL,
},
}
forceHTTPS := utils.IsTruthy(meta.ForceHTTPS)
conf := &oauth2.Config{
ClientID: meta.ClientID,
ClientSecret: meta.ClientSecret,
Scopes: strings.Split(meta.Scopes, ","),
RedirectURL: meta.RedirectURL,
Endpoint: oauth2.Endpoint{
AuthURL: meta.AuthURL,
TokenURL: meta.TokenURL,
},
}
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
session := sessions.Start(w, r)
session := sessions.StartFasthttp(ctx)
if session.GetString(meta.AuthHeaderName) != "" {
ctx.Request.Header.Add(meta.AuthHeaderName, session.GetString(meta.AuthHeaderName))
h(ctx)
w.Header().Add(meta.AuthHeaderName, session.GetString(meta.AuthHeaderName))
next.ServeHTTP(w, r)
return
}
state := string(ctx.FormValue(stateParam))
//nolint:nestif
state := r.URL.Query().Get(stateParam)
if state == "" {
id, err := uuid.NewRandom()
if err != nil {
ctx.Error(fasthttp.StatusMessage(fasthttp.StatusInternalServerError), fasthttp.StatusInternalServerError)
httputils.RespondWithError(w, http.StatusInternalServerError)
m.logger.Errorf("Failed to generate UUID: %v", err)
return
}
session.Set(savedState, id.String())
session.Set(redirectPath, string(ctx.RequestURI()))
url := conf.AuthCodeURL(id.String(), oauth2.AccessTypeOffline)
ctx.Redirect(url, 302)
idStr := id.String()
session.Set(savedState, idStr)
session.Set(redirectPath, r.URL)
url := conf.AuthCodeURL(idStr, oauth2.AccessTypeOffline)
httputils.RespondWithRedirect(w, http.StatusFound, url)
} else {
authState := session.GetString(savedState)
redirectURL := session.GetString(redirectPath)
if strings.EqualFold(meta.ForceHTTPS, "true") {
redirectURL = https + string(ctx.Request.Host()) + redirectURL
redirectURL, ok := session.Get(redirectPath).(*url.URL)
if !ok {
httputils.RespondWithError(w, http.StatusInternalServerError)
m.logger.Errorf("Value saved in state key '%s' is not a *url.URL", redirectPath)
return
}
if state != authState {
ctx.Error("invalid state", fasthttp.StatusBadRequest)
} else {
code := string(ctx.FormValue(codeParam))
if code == "" {
ctx.Error("code not found", fasthttp.StatusBadRequest)
return
}
token, err := conf.Exchange(context.Background(), code)
if err != nil {
ctx.Error(err.Error(), fasthttp.StatusInternalServerError)
return
}
session.Set(meta.AuthHeaderName, token.Type()+" "+token.AccessToken)
ctx.Request.Header.Add(meta.AuthHeaderName, token.Type()+" "+token.AccessToken)
ctx.Redirect(redirectURL, 302)
if forceHTTPS {
redirectURL.Scheme = "https"
}
if state != authState {
httputils.RespondWithErrorAndMessage(w, http.StatusBadRequest, "invalid state")
return
}
code := r.URL.Query().Get(codeParam)
if code == "" {
httputils.RespondWithErrorAndMessage(w, http.StatusBadRequest, "code not found")
return
}
token, err := conf.Exchange(r.Context(), code)
if err != nil {
httputils.RespondWithError(w, http.StatusInternalServerError)
m.logger.Error("Failed to exchange token")
return
}
authHeader := token.Type() + " " + token.AccessToken
session.Set(meta.AuthHeaderName, authHeader)
w.Header().Add(meta.AuthHeaderName, authHeader)
httputils.RespondWithRedirect(w, http.StatusFound, redirectURL.String())
}
}
})
}, nil
}
func (m *Middleware) getNativeMetadata(metadata middleware.Metadata) (*oAuth2MiddlewareMetadata, error) {
b, err := json.Marshal(metadata.Properties)
if err != nil {
return nil, err
}
var middlewareMetadata oAuth2MiddlewareMetadata
err = json.Unmarshal(b, &middlewareMetadata)
err := mdutils.DecodeMetadata(metadata.Properties, &middlewareMetadata)
if err != nil {
return nil, err
}
return &middlewareMetadata, nil
}

View File

@ -16,18 +16,18 @@ package oauth2clientcredentials
import (
"context"
"crypto/sha256"
"encoding/json"
"encoding/hex"
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"github.com/patrickmn/go-cache"
"github.com/valyala/fasthttp"
"golang.org/x/oauth2"
"golang.org/x/oauth2/clientcredentials"
mdutils "github.com/dapr/components-contrib/metadata"
"github.com/dapr/components-contrib/middleware"
"github.com/dapr/kit/logger"
)
@ -40,8 +40,7 @@ type oAuth2ClientCredentialsMiddlewareMetadata struct {
TokenURL string `json:"tokenURL"`
HeaderName string `json:"headerName"`
EndpointParamsQuery string `json:"endpointParamsQuery,omitempty"`
AuthStyleString string `json:"authStyle"`
AuthStyle int `json:"-"`
AuthStyle int `json:"authStyle"`
}
// TokenProviderInterface provides a common interface to Mock the Token retrieval in unit tests.
@ -69,53 +68,47 @@ type Middleware struct {
}
// GetHandler retruns the HTTP handler provided by the middleware.
func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.RequestHandler) fasthttp.RequestHandler, error) {
func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(next http.Handler) http.Handler, error) {
meta, err := m.getNativeMetadata(metadata)
if err != nil {
m.log.Errorf("getNativeMetadata error, %s", err)
m.log.Errorf("getNativeMetadata error: %s", err)
return nil, err
}
return func(h fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
var headerValue string
// Check if valid Token is in the cache
cacheKey := m.getCacheKey(meta)
cachedToken, found := m.tokenCache.Get(cacheKey)
endpointParams, err := url.ParseQuery(meta.EndpointParamsQuery)
if err != nil {
m.log.Warnf("Error parsing endpoint parameters: %s", err)
endpointParams, _ = url.ParseQuery("")
}
conf := &clientcredentials.Config{
ClientID: meta.ClientID,
ClientSecret: meta.ClientSecret,
Scopes: strings.Split(meta.Scopes, ","),
TokenURL: meta.TokenURL,
EndpointParams: endpointParams,
AuthStyle: oauth2.AuthStyle(meta.AuthStyle),
}
cacheKey := m.getCacheKey(meta)
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var headerValue string
// Check if valid token is in the cache
cachedToken, found := m.tokenCache.Get(cacheKey)
if !found {
m.log.Debugf("Cached token not found, try get one")
endpointParams, err := url.ParseQuery(meta.EndpointParamsQuery)
token, err := m.tokenProvider.GetToken(conf)
if err != nil {
m.log.Errorf("Error parsing endpoint parameters, %s", err)
endpointParams, _ = url.ParseQuery("")
}
conf := &clientcredentials.Config{
ClientID: meta.ClientID,
ClientSecret: meta.ClientSecret,
Scopes: strings.Split(meta.Scopes, ","),
TokenURL: meta.TokenURL,
EndpointParams: endpointParams,
AuthStyle: oauth2.AuthStyle(meta.AuthStyle),
}
token, tokenError := m.tokenProvider.GetToken(conf)
if tokenError != nil {
m.log.Errorf("Error acquiring token, %s", tokenError)
m.log.Errorf("Error acquiring token: %s", err)
return
}
tokenExpirationDuration := token.Expiry.Sub(time.Now().In(time.UTC))
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
}
tokenExpirationDuration := token.Expiry.Sub(time.Now())
m.log.Debugf("Token expires at %s (%s from now)", token.Expiry, tokenExpirationDuration)
headerValue = token.Type() + " " + token.AccessToken
m.tokenCache.Set(cacheKey, headerValue, tokenExpirationDuration)
@ -124,46 +117,37 @@ func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.R
headerValue = cachedToken.(string)
}
ctx.Request.Header.Add(meta.HeaderName, headerValue)
h(ctx)
}
w.Header().Add(meta.HeaderName, headerValue)
next.ServeHTTP(w, r)
})
}, nil
}
func (m *Middleware) getNativeMetadata(metadata middleware.Metadata) (*oAuth2ClientCredentialsMiddlewareMetadata, error) {
b, err := json.Marshal(metadata.Properties)
if err != nil {
return nil, err
}
var middlewareMetadata oAuth2ClientCredentialsMiddlewareMetadata
err = json.Unmarshal(b, &middlewareMetadata)
err := mdutils.DecodeMetadata(metadata.Properties, &middlewareMetadata)
if err != nil {
return nil, err
return nil, fmt.Errorf("metadata errors: %w", err)
}
// Do input validation checks
errorString := ""
// Check if values are present
m.checkMetadataValueExists(&errorString, &middlewareMetadata.HeaderName, "headerName")
m.checkMetadataValueExists(&errorString, &middlewareMetadata.ClientID, "clientID")
m.checkMetadataValueExists(&errorString, &middlewareMetadata.ClientSecret, "clientSecret")
m.checkMetadataValueExists(&errorString, &middlewareMetadata.Scopes, "scopes")
m.checkMetadataValueExists(&errorString, &middlewareMetadata.TokenURL, "tokenURL")
m.checkMetadataValueExists(&errorString, &middlewareMetadata.AuthStyleString, "authStyle")
// Converting AuthStyle to int and do a value check
authStyle, err := strconv.Atoi(middlewareMetadata.AuthStyleString)
if err != nil {
errorString += fmt.Sprintf("Parameter 'authStyle' can only have the values 0,1,2. Received: '%s'. ", middlewareMetadata.AuthStyleString)
} else if authStyle < 0 || authStyle > 2 {
errorString += fmt.Sprintf("Parameter 'authStyle' can only have the values 0,1,2. Received: '%d'. ", authStyle)
} else {
middlewareMetadata.AuthStyle = authStyle
// Value-check AuthStyle
if middlewareMetadata.AuthStyle < 0 || middlewareMetadata.AuthStyle > 2 {
errorString += fmt.Sprintf("Parameter 'authStyle' can only have the values 0,1,2. Received: '%d'. ", middlewareMetadata.AuthStyle)
}
// Return errors if any found
if errorString != "" {
return nil, fmt.Errorf("%s", errorString)
return nil, fmt.Errorf("metadata errors: %s", errorString)
}
return &middlewareMetadata, nil
@ -177,11 +161,8 @@ func (m *Middleware) checkMetadataValueExists(errorString *string, metadataValue
func (m *Middleware) getCacheKey(meta *oAuth2ClientCredentialsMiddlewareMetadata) string {
// we will hash the key components ClientID + Scopes is a unique composite key/identifier for a token
hashedKey := sha256.New()
key := strings.Join([]string{meta.ClientID, meta.Scopes}, "")
hashedKey.Write([]byte(key))
return fmt.Sprintf("%x", hashedKey.Sum(nil))
hashedKey := sha256.Sum224([]byte(meta.ClientID + meta.Scopes))
return hex.EncodeToString(hashedKey[:])
}
// SetTokenProvider will enable to change the tokenProvider used after instanciation (needed for mocking).

View File

@ -14,13 +14,14 @@ limitations under the License.
package oauth2clientcredentials
import (
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
fh "github.com/valyala/fasthttp"
oauth2 "golang.org/x/oauth2"
"github.com/dapr/components-contrib/middleware"
@ -28,7 +29,11 @@ import (
"github.com/dapr/kit/logger"
)
func mockedRequestHandler(ctx *fh.RequestCtx) {}
// mockedRequestHandler acts like an upstream service returns success status code 200 and a fixed response body.
func mockedRequestHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("from mock"))
}
// TestOAuth2ClientCredentialsMetadata will check
// - if the metadata checks are correct in place.
@ -41,7 +46,7 @@ func TestOAuth2ClientCredentialsMetadata(t *testing.T) {
log := logger.NewLogger("oauth2clientcredentials.test")
_, err := NewOAuth2ClientCredentialsMiddleware(log).GetHandler(metadata)
assert.EqualError(t, err, "Parameter 'headerName' needs to be set. Parameter 'clientID' needs to be set. Parameter 'clientSecret' needs to be set. Parameter 'scopes' needs to be set. Parameter 'tokenURL' needs to be set. Parameter 'authStyle' needs to be set. Parameter 'authStyle' can only have the values 0,1,2. Received: ''. ")
assert.EqualError(t, err, "metadata errors: Parameter 'headerName' needs to be set. Parameter 'clientID' needs to be set. Parameter 'clientSecret' needs to be set. Parameter 'scopes' needs to be set. Parameter 'tokenURL' needs to be set. ")
// Invalid authStyle (non int)
metadata.Properties = map[string]string{
@ -53,17 +58,17 @@ func TestOAuth2ClientCredentialsMetadata(t *testing.T) {
"authStyle": "asdf", // This is the value to test
}
_, err2 := NewOAuth2ClientCredentialsMiddleware(log).GetHandler(metadata)
assert.EqualError(t, err2, "Parameter 'authStyle' can only have the values 0,1,2. Received: 'asdf'. ")
assert.EqualError(t, err2, "metadata errors: 1 error(s) decoding:\n\n* cannot parse 'AuthStyle' as int: strconv.ParseInt: parsing \"asdf\": invalid syntax")
// Invalid authStyle (int > 2)
metadata.Properties["authStyle"] = "3"
_, err3 := NewOAuth2ClientCredentialsMiddleware(log).GetHandler(metadata)
assert.EqualError(t, err3, "Parameter 'authStyle' can only have the values 0,1,2. Received: '3'. ")
assert.EqualError(t, err3, "metadata errors: Parameter 'authStyle' can only have the values 0,1,2. Received: '3'. ")
// Invalid authStyle (int < 0)
metadata.Properties["authStyle"] = "-1"
_, err4 := NewOAuth2ClientCredentialsMiddleware(log).GetHandler(metadata)
assert.EqualError(t, err4, "Parameter 'authStyle' can only have the values 0,1,2. Received: '-1'. ")
assert.EqualError(t, err4, "metadata errors: Parameter 'authStyle' can only have the values 0,1,2. Received: '-1'. ")
}
// TestOAuth2ClientCredentialsToken will check
@ -108,10 +113,12 @@ func TestOAuth2ClientCredentialsToken(t *testing.T) {
require.NoError(t, err)
// First handler call should return abc Token
var requestContext1 fh.RequestCtx
handler(mockedRequestHandler)(&requestContext1)
r := httptest.NewRequest(http.MethodGet, "http://dapr.io", nil)
w := httptest.NewRecorder()
handler(http.HandlerFunc(mockedRequestHandler)).ServeHTTP(w, r)
// Assertion
assert.Equal(t, "Bearer abcd", string(requestContext1.Request.Header.Peek("someHeader")))
assert.Equal(t, "Bearer abcd", w.Header().Get("someHeader"))
}
// TestOAuth2ClientCredentialsCache will check
@ -166,23 +173,29 @@ func TestOAuth2ClientCredentialsCache(t *testing.T) {
require.NoError(t, err)
// First handler call should return abc Token
var requestContext1 fh.RequestCtx
handler(mockedRequestHandler)(&requestContext1)
r := httptest.NewRequest(http.MethodGet, "http://dapr.io", nil)
w := httptest.NewRecorder()
handler(http.HandlerFunc(mockedRequestHandler)).ServeHTTP(w, r)
// Assertion
assert.Equal(t, "Bearer abc", string(requestContext1.Request.Header.Peek("someHeader")))
assert.Equal(t, "Bearer abc", w.Header().Get("someHeader"))
// Second handler call should still return 'cached' abc Token
var requestContext2 fh.RequestCtx
handler(mockedRequestHandler)(&requestContext2)
r = httptest.NewRequest(http.MethodGet, "http://dapr.io", nil)
w = httptest.NewRecorder()
handler(http.HandlerFunc(mockedRequestHandler)).ServeHTTP(w, r)
// Assertion
assert.Equal(t, "Bearer abc", string(requestContext2.Request.Header.Peek("someHeader")))
assert.Equal(t, "Bearer abc", w.Header().Get("someHeader"))
// Wait at a second to invalidate cache entry for abc
time.Sleep(1 * time.Second)
// Third call should return def Token
var requestContext3 fh.RequestCtx
handler(mockedRequestHandler)(&requestContext3)
r = httptest.NewRequest(http.MethodGet, "http://dapr.io", nil)
w = httptest.NewRecorder()
handler(http.HandlerFunc(mockedRequestHandler)).ServeHTTP(w, r)
// Assertion
assert.Equal(t, "MAC def", string(requestContext3.Request.Header.Peek("someHeader")))
assert.Equal(t, "MAC def", w.Header().Get("someHeader"))
}

View File

@ -19,13 +19,19 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"math"
"net/http"
"net/textproto"
"strconv"
"strings"
"time"
"github.com/open-policy-agent/opa/rego"
"github.com/valyala/fasthttp"
"k8s.io/utils/strings/slices"
"github.com/dapr/components-contrib/internal/httputils"
"github.com/dapr/components-contrib/internal/utils"
"github.com/dapr/components-contrib/middleware"
"github.com/dapr/kit/logger"
)
@ -33,9 +39,11 @@ import (
type Status int
type middlewareMetadata struct {
Rego string `json:"rego"`
DefaultStatus Status `json:"defaultStatus,omitempty"`
IncludedHeaders string `json:"includedHeaders,omitempty"`
Rego string `json:"rego"`
DefaultStatus Status `json:"defaultStatus,omitempty"`
IncludedHeaders string `json:"includedHeaders,omitempty"`
ReadBody string `json:"readBody,omitempty"`
includedHeadersParsed []string `json:"-"`
}
// NewMiddleware returns a new Open Policy Agent middleware.
@ -98,110 +106,98 @@ func (s *Status) Valid() bool {
}
// GetHandler returns the HTTP handler provided by the middleware.
func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.RequestHandler) fasthttp.RequestHandler, error) {
func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(next http.Handler) http.Handler, error) {
meta, err := m.getNativeMetadata(metadata)
if err != nil {
return nil, err
}
ctx := context.Background()
ctx, cancel := context.WithTimeout(context.TODO(), time.Minute)
query, err := rego.New(
rego.Query("result = data.http.allow"),
rego.Module("inline.rego", meta.Rego),
).PrepareForEval(ctx)
cancel()
if err != nil {
return nil, err
}
return func(h fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
if allow := m.evalRequest(ctx, meta, &query); !allow {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if allow := m.evalRequest(w, r, meta, &query); !allow {
return
}
h(ctx)
}
next.ServeHTTP(w, r)
})
}, nil
}
func (m *Middleware) evalRequest(ctx *fasthttp.RequestCtx, meta *middlewareMetadata, query *rego.PreparedEvalQuery) bool {
func (m *Middleware) evalRequest(w http.ResponseWriter, r *http.Request, 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 {
scrubbedHeader := strings.ReplaceAll(allowedHeader, " ", "")
buf := []byte("")
result := fasthttp.AppendNormalizedHeaderKeyBytes(buf, []byte(scrubbedHeader))
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)}
for key, value := range r.Header {
if len(value) > 0 && slices.Contains(meta.includedHeadersParsed, key) {
headers[key] = strings.Join(value, ", ")
}
})
}
path := string(ctx.Path())
pathParts := strings.Split(strings.Trim(path, "/"), "/")
var body string
if utils.IsTruthy(meta.ReadBody) {
buf, _ := io.ReadAll(r.Body)
body = string(buf)
// Put the body back in the request
r.Body = io.NopCloser(bytes.NewBuffer(buf))
}
pathParts := strings.Split(strings.Trim(r.URL.Path, "/"), "/")
input := map[string]interface{}{
"request": map[string]interface{}{
"method": string(ctx.Method()),
"path": path,
"method": r.Method,
"path": r.URL.Path,
"path_parts": pathParts,
"raw_query": string(ctx.QueryArgs().QueryString()),
"query": queryArgs,
"raw_query": r.URL.RawQuery,
"query": map[string][]string(r.URL.Query()),
"headers": headers,
"scheme": string(ctx.Request.URI().Scheme()),
"body": string(ctx.Request.Body()),
"scheme": r.URL.Scheme,
"body": body,
},
}
results, err := query.Eval(context.TODO(), rego.EvalInput(input))
results, err := query.Eval(r.Context(), rego.EvalInput(input))
if err != nil {
m.opaError(ctx, meta, err)
m.opaError(w, meta, err)
return false
}
if len(results) == 0 {
m.opaError(ctx, meta, errOpaNoResult)
m.opaError(w, meta, errOpaNoResult)
return false
}
return m.handleRegoResult(ctx, meta, results[0].Bindings["result"])
return m.handleRegoResult(w, 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 {
func (m *Middleware) handleRegoResult(w http.ResponseWriter, meta *middlewareMetadata, result any) bool {
if allowed, ok := result.(bool); ok {
if !allowed {
ctx.Error(fasthttp.StatusMessage(int(meta.DefaultStatus)), int(meta.DefaultStatus))
httputils.RespondWithError(w, int(meta.DefaultStatus))
}
return allowed
}
if _, ok := result.(map[string]interface{}); !ok {
m.opaError(ctx, meta, errOpaInvalidResultType)
if _, ok := result.(map[string]any); !ok {
m.opaError(w, 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)
m.opaError(w, meta, err)
return false
}
@ -212,31 +208,26 @@ func (m *Middleware) handleRegoResult(ctx *fasthttp.RequestCtx, meta *middleware
}
if err = json.Unmarshal(marshaled, &regoResult); err != nil {
m.opaError(ctx, meta, err)
m.opaError(w, 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).
// Set the headers on the ongoing request (overriding as necessary)
for key, value := range regoResult.AdditionalHeaders {
w.Header().Set(key, value)
}
// If the result isn't allowed, set the response status
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)
}
httputils.RespondWithError(w, regoResult.StatusCode)
}
return regoResult.Allow
}
func (m *Middleware) opaError(ctx *fasthttp.RequestCtx, meta *middlewareMetadata, err error) {
ctx.Error(fasthttp.StatusMessage(int(meta.DefaultStatus)), int(meta.DefaultStatus))
ctx.Response.Header.Set(opaErrorHeaderKey, "true")
func (m *Middleware) opaError(w http.ResponseWriter, meta *middlewareMetadata, err error) {
w.Header().Set(opaErrorHeaderKey, "true")
httputils.RespondWithError(w, int(meta.DefaultStatus))
m.logger.Warnf("Error procesing rego policy: %v", err)
}
@ -254,5 +245,16 @@ func (m *Middleware) getNativeMetadata(metadata middleware.Metadata) (*middlewar
return nil, err
}
meta.includedHeadersParsed = strings.Split(meta.IncludedHeaders, ",")
n := 0
for i := range meta.includedHeadersParsed {
scrubbed := strings.ReplaceAll(meta.includedHeadersParsed[i], " ", "")
if scrubbed != "" {
meta.includedHeadersParsed[n] = textproto.CanonicalMIMEHeaderKey(scrubbed)
n++
}
}
meta.includedHeadersParsed = meta.includedHeadersParsed[:n]
return &meta, nil
}

View File

@ -15,11 +15,13 @@ package opa
import (
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
fh "github.com/valyala/fasthttp"
"github.com/dapr/components-contrib/metadata"
"github.com/dapr/components-contrib/middleware"
@ -27,17 +29,15 @@ import (
)
// mockedRequestHandler acts like an upstream service returns success status code 200 and a fixed response body.
func mockedRequestHandler(ctx *fh.RequestCtx) {
ctx.Response.SetStatusCode(200)
ctx.Response.SetBody([]byte("from mock"))
func mockedRequestHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("from mock"))
}
type RequestConfiguator func(*fh.RequestCtx)
func TestOpaPolicy(t *testing.T) {
tests := map[string]struct {
meta middleware.Metadata
req RequestConfiguator
req func() *http.Request
status int
headers *[][]string
body []string
@ -124,9 +124,8 @@ func TestOpaPolicy(t *testing.T) {
`,
},
}},
req: func(ctx *fh.RequestCtx) {
ctx.Request.SetHost("https://my.site")
ctx.Request.URI().SetPath("/allowed")
req: func() *http.Request {
return httptest.NewRequest(http.MethodGet, "https://my.site/allowed", nil)
},
status: 200,
},
@ -143,9 +142,8 @@ func TestOpaPolicy(t *testing.T) {
`,
},
}},
req: func(ctx *fh.RequestCtx) {
ctx.Request.SetHost("https://my.site")
ctx.Request.URI().SetPath("/forbidden")
req: func() *http.Request {
return httptest.NewRequest(http.MethodGet, "https://my.site/forbidden", nil)
},
status: 403,
},
@ -162,9 +160,10 @@ func TestOpaPolicy(t *testing.T) {
`,
},
}},
req: func(ctx *fh.RequestCtx) {
ctx.Request.SetHost("https://my.site")
ctx.Request.Header.Add("x-bad-header", "1")
req: func() *http.Request {
r := httptest.NewRequest(http.MethodGet, "https://my.site", nil)
r.Header.Add("x-bad-header", "1")
return r
},
status: 200,
},
@ -182,9 +181,10 @@ func TestOpaPolicy(t *testing.T) {
"includedHeaders": "x-bad-header",
},
}},
req: func(ctx *fh.RequestCtx) {
ctx.Request.SetHost("https://my.site")
ctx.Request.Header.Add("x-bad-header", "1")
req: func() *http.Request {
r := httptest.NewRequest(http.MethodGet, "https://my.site", nil)
r.Header.Add("X-BAD-HEADER", "1")
return r
},
status: 403,
},
@ -242,30 +242,50 @@ func TestOpaPolicy(t *testing.T) {
"allow on body contains allow": {
meta: middleware.Metadata{Base: metadata.Base{
Properties: map[string]string{
"readBody": "true",
"rego": `
package http
default allow = false
allow = { "status_code": 200 } {
allow = { "allow": true } {
input.request.body == "allow"
}
`,
},
}},
req: func(ctx *fh.RequestCtx) {
ctx.SetContentType("text/plain; charset=utf8")
ctx.Request.SetHost("https://my.site")
ctx.Request.SetBodyString("allow")
req: func() *http.Request {
r := httptest.NewRequest(http.MethodGet, "https://my.site", strings.NewReader("allow"))
r.Header.Add("content-type", "text/plain; charset=utf8")
return r
},
status: 200,
},
"body is not read by default": {
meta: middleware.Metadata{Base: metadata.Base{
Properties: map[string]string{
// `"readBody": "false"` is the default value
"rego": `
package http
default allow = false
allow = { "allow": true } {
input.request.body == "allow"
}
`,
},
}},
req: func() *http.Request {
r := httptest.NewRequest(http.MethodGet, "https://my.site", strings.NewReader("allow"))
r.Header.Add("content-type", "text/plain; charset=utf8")
return r
},
status: 403,
},
"allow when multiple headers included with space": {
meta: middleware.Metadata{Base: metadata.Base{
Properties: map[string]string{
"rego": `
package http
default allow = false
allow = { "status_code": 200 } {
allow = { "allow": true } {
input.request.headers["X-Jwt-Header"]
input.request.headers["X-My-Custom-Header"]
}
@ -273,47 +293,76 @@ func TestOpaPolicy(t *testing.T) {
"includedHeaders": "x-my-custom-header, x-jwt-header",
},
}},
req: func(ctx *fh.RequestCtx) {
ctx.Request.SetHost("https://my.site")
ctx.Request.Header.Add("x-jwt-header", "1")
ctx.Request.Header.Add("x-my-custom-header", "2")
req: func() *http.Request {
r := httptest.NewRequest(http.MethodGet, "https://my.site", nil)
r.Header.Add("x-jwt-header", "1")
r.Header.Add("x-my-custom-header", "2")
return r
},
status: 200,
},
"reject when multiple headers included with space": {
meta: middleware.Metadata{Base: metadata.Base{
Properties: map[string]string{
"rego": `
package http
default allow = false
allow = { "allow": true } {
input.request.headers["X-Jwt-Header"]
input.request.headers["X-My-Custom-Header"]
}
`,
"includedHeaders": "x-my-custom-header, x-jwt-header",
},
}},
req: func() *http.Request {
r := httptest.NewRequest(http.MethodGet, "https://my.site", nil)
r.Header.Add("x-jwt-header", "1")
r.Header.Add("x-bad-header", "2")
return r
},
status: 403,
},
}
log := logger.NewLogger("opa.test")
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)
handler, err := opaMiddleware.GetHandler(test.meta)
if test.shouldHandlerError {
require.Error(t, err)
return
}
require.NoError(t, err)
var reqCtx fh.RequestCtx
var r *http.Request
if test.req != nil {
test.req(&reqCtx)
r = test.req()
} else {
r = httptest.NewRequest(http.MethodGet, "https://my.site", nil)
}
handler(mockedRequestHandler)(&reqCtx)
w := httptest.NewRecorder()
handler(http.HandlerFunc(mockedRequestHandler)).ServeHTTP(w, r)
if test.shouldRegoError {
assert.Equal(t, 403, reqCtx.Response.StatusCode())
assert.Equal(t, "true", string(reqCtx.Response.Header.Peek(opaErrorHeaderKey)))
assert.Equal(t, 403, w.Code)
assert.Equal(t, "true", w.Header().Get(opaErrorHeaderKey))
return
}
assert.Equal(t, test.status, reqCtx.Response.StatusCode())
assert.Equal(t, test.status, w.Code)
if test.status == 200 {
assert.Equal(t, "from mock", w.Body.String())
}
if test.headers != nil {
for _, header := range *test.headers {
assert.Equal(t, header[1], string(reqCtx.Response.Header.Peek(header[0])))
assert.Equal(t, header[1], w.Header().Get(header[0]))
}
}
})

View File

@ -15,14 +15,12 @@ package ratelimit
import (
"fmt"
"net/http"
"strconv"
"github.com/didip/tollbooth"
"github.com/valyala/fasthttp"
"github.com/valyala/fasthttp/fasthttpadaptor"
"github.com/dapr/components-contrib/middleware"
"github.com/dapr/components-contrib/middleware/http/nethttpadaptor"
"github.com/dapr/kit/logger"
)
@ -39,17 +37,15 @@ const (
)
// NewRateLimitMiddleware returns a new ratelimit middleware.
func NewRateLimitMiddleware(logger logger.Logger) middleware.Middleware {
return &Middleware{logger: logger}
func NewRateLimitMiddleware(_ logger.Logger) middleware.Middleware {
return &Middleware{}
}
// Middleware is an ratelimit middleware.
type Middleware struct {
logger logger.Logger
}
type Middleware struct{}
// GetHandler returns the HTTP handler provided by the middleware.
func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.RequestHandler) fasthttp.RequestHandler, error) {
func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(next http.Handler) http.Handler, error) {
meta, err := m.getNativeMetadata(metadata)
if err != nil {
return nil, err
@ -57,13 +53,8 @@ func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.R
limiter := tollbooth.NewLimiter(meta.MaxRequestsPerSecond, nil)
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)
}
return func(next http.Handler) http.Handler {
return tollbooth.LimitHandler(limiter, next)
}, nil
}
@ -74,7 +65,7 @@ func (m *Middleware) getNativeMetadata(metadata middleware.Metadata) (*rateLimit
if val, ok := metadata.Properties[maxRequestsPerSecondKey]; ok {
f, err := strconv.ParseFloat(val, 64)
if err != nil {
return nil, fmt.Errorf("error parsing ratelimit middleware property %s: %+v", maxRequestsPerSecondKey, err)
return nil, fmt.Errorf("error parsing ratelimit middleware property %s: %w", maxRequestsPerSecondKey, err)
}
if f <= 0 {
return nil, fmt.Errorf("ratelimit middleware property %s must be a positive value", maxRequestsPerSecondKey)

View File

@ -0,0 +1,90 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package routeralias
import (
"context"
"fmt"
"net/http"
"github.com/dapr/components-contrib/middleware"
"github.com/dapr/kit/logger"
"github.com/gorilla/mux"
)
type contextKey int
const varsKey contextKey = iota
// Middleware is an routeralias middleware.
type Middleware struct {
logger logger.Logger
router *mux.Router
}
// NewMiddleware returns a new routerchecker middleware.
func NewMiddleware(logger logger.Logger) middleware.Middleware {
return &Middleware{logger: logger}
}
// GetHandler retruns the HTTP handler provided by the middleware.
func (m *Middleware) GetHandler(metadata middleware.Metadata) (
func(next http.Handler) http.Handler, error,
) {
if err := m.getNativeMetadata(metadata); err != nil {
return nil, err
}
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var match mux.RouteMatch
if m.router.Match(r, &match) {
ctx := context.WithValue(r.Context(), varsKey, match.Vars)
r = r.WithContext(ctx)
match.Handler.ServeHTTP(w, r)
}
next.ServeHTTP(w, r)
})
}, nil
}
func (m *Middleware) getNativeMetadata(metadata middleware.Metadata) error {
m.router = mux.NewRouter()
for key, value := range metadata.Properties {
m.router.Handle(key, m.routerConvert(value))
}
return nil
}
func (m *Middleware) routerConvert(daprRouter string) http.Handler {
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
params := vars(req)
vals := req.URL.Query()
for key, val := range params {
vals.Add(key, val)
}
req.URL.RawQuery = vals.Encode()
req.URL.Path = daprRouter
req.RequestURI = fmt.Sprintf("%s?%s", daprRouter, req.URL.RawQuery)
})
}
// vars returns the route variables for the current request, if any.
func vars(r *http.Request) map[string]string {
if rv := r.Context().Value(varsKey); rv != nil {
return rv.(map[string]string)
}
return nil
}

View File

@ -0,0 +1,114 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package routeralias
import (
"io"
"net/http"
"net/http/httptest"
"testing"
"github.com/dapr/components-contrib/internal/httputils"
"github.com/dapr/components-contrib/metadata"
"github.com/dapr/components-contrib/middleware"
"github.com/dapr/kit/logger"
"github.com/stretchr/testify/assert"
)
// mockedRequestHandler acts like an upstream service returns success status code 200 and a fixed response body.
func mockedRequestHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
uri := httputils.RequestURI(r)
w.Write([]byte(uri))
}
func TestRequestHandlerWithIllegalRouterRule(t *testing.T) {
meta := middleware.Metadata{
Base: metadata.Base{
Properties: map[string]string{
"/v1.0/mall/activity/info": "/v1.0/invoke/srv.default/method/mall/activity/info",
"/v1.0/hello/activity/{id}/info": "/v1.0/invoke/srv.default/method/hello/activity/info",
"/v1.0/hello/activity/{id}/user": "/v1.0/invoke/srv.default/method/hello/activity/user",
},
},
}
log := logger.NewLogger("routeralias.test")
ralias := NewMiddleware(log)
handler, err := ralias.GetHandler(meta)
assert.Nil(t, err)
t.Run("hit: change router with common request", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet,
"http://localhost:5001/v1.0/mall/activity/info?id=123", nil)
w := httptest.NewRecorder()
handler(http.HandlerFunc(mockedRequestHandler)).ServeHTTP(w, r)
msg, err := io.ReadAll(w.Body)
assert.Nil(t, err)
result := w.Result()
assert.Equal(t, http.StatusOK, result.StatusCode)
assert.Equal(t,
"/v1.0/invoke/srv.default/method/mall/activity/info?id=123",
string(msg))
result.Body.Close()
})
t.Run("hit: change router with restful request", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet,
"http://localhost:5001/v1.0/hello/activity/1/info", nil)
w := httptest.NewRecorder()
handler(http.HandlerFunc(mockedRequestHandler)).ServeHTTP(w, r)
msg, err := io.ReadAll(w.Body)
assert.Nil(t, err)
result := w.Result()
assert.Equal(t, http.StatusOK, result.StatusCode)
assert.Equal(t,
"/v1.0/invoke/srv.default/method/hello/activity/info?id=1",
string(msg))
result.Body.Close()
})
t.Run("hit: change router with restful request and query string", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet,
"http://localhost:5001/v1.0/hello/activity/1/user?userid=123", nil)
w := httptest.NewRecorder()
handler(http.HandlerFunc(mockedRequestHandler)).ServeHTTP(w, r)
msg, err := io.ReadAll(w.Body)
assert.Nil(t, err)
result := w.Result()
assert.Equal(t, http.StatusOK, result.StatusCode)
assert.Equal(t,
"/v1.0/invoke/srv.default/method/hello/activity/user?id=1&userid=123",
string(msg))
result.Body.Close()
})
t.Run("miss: no change router", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet,
"http://localhost:5001/v1.0/invoke/srv.default", nil)
w := httptest.NewRecorder()
handler(http.HandlerFunc(mockedRequestHandler)).ServeHTTP(w, r)
msg, err := io.ReadAll(w.Body)
assert.Nil(t, err)
result := w.Result()
assert.Equal(t, http.StatusOK, result.StatusCode)
assert.Equal(t,
"/v1.0/invoke/srv.default",
string(msg))
result.Body.Close()
})
}

View File

@ -14,11 +14,12 @@ limitations under the License.
package routerchecker
import (
"encoding/json"
"fmt"
"net/http"
"regexp"
"github.com/valyala/fasthttp"
"github.com/dapr/components-contrib/internal/httputils"
mdutils "github.com/dapr/components-contrib/metadata"
"github.com/dapr/components-contrib/middleware"
"github.com/dapr/kit/logger"
)
@ -39,44 +40,34 @@ type Middleware struct {
}
// GetHandler retruns the HTTP handler provided by the middleware.
func (m *Middleware) GetHandler(metadata middleware.Metadata) (
func(h fasthttp.RequestHandler) fasthttp.RequestHandler, error,
) {
func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(next http.Handler) http.Handler, error) {
meta, err := m.getNativeMetadata(metadata)
if err != nil {
return nil, err
}
return func(h fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
isPass, err := regexp.MatchString(meta.Rule, string(ctx.RequestURI()))
if err != nil {
m.logger.Error("regexp match failed", err.Error())
ctx.Error("regexp match failed", fasthttp.StatusBadRequest)
re, err := regexp.Compile(meta.Rule)
if err != nil {
return nil, fmt.Errorf("failed to compile rule regexp: %w", err)
}
return
}
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
isPass := re.MatchString(httputils.RequestURI(r))
if !isPass {
ctx.Error("invalid router", fasthttp.StatusBadRequest)
httputils.RespondWithErrorAndMessage(w, http.StatusBadRequest, "invalid router")
return
}
h(ctx)
}
next.ServeHTTP(w, r)
})
}, nil
}
func (m *Middleware) getNativeMetadata(metadata middleware.Metadata) (*Metadata, error) {
b, err := json.Marshal(metadata.Properties)
if err != nil {
return nil, err
}
var middlewareMetadata Metadata
err = json.Unmarshal(b, &middlewareMetadata)
err := mdutils.DecodeMetadata(metadata.Properties, &middlewareMetadata)
if err != nil {
return nil, err
}
return &middlewareMetadata, nil
}

View File

@ -14,20 +14,21 @@ limitations under the License.
package routerchecker
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
"github.com/valyala/fasthttp"
"github.com/dapr/components-contrib/metadata"
"github.com/dapr/components-contrib/middleware"
"github.com/dapr/kit/logger"
)
type RouterOutput struct{}
func (ro *RouterOutput) handle(ctx *fasthttp.RequestCtx) {
ctx.Error(string(ctx.RequestURI()), fasthttp.StatusOK)
// mockedRequestHandler acts like an upstream service returns success status code 200 and a fixed response body.
func mockedRequestHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("from mock"))
}
func TestRequestHandlerWithIllegalRouterRule(t *testing.T) {
@ -39,14 +40,11 @@ func TestRequestHandlerWithIllegalRouterRule(t *testing.T) {
handler, err := rchecker.GetHandler(meta)
assert.Nil(t, err)
var ctx fasthttp.RequestCtx
ctx.Request.SetHost("localhost:5001")
ctx.Request.SetRequestURI("/v1.0/invoke/qcg.default/method/ cat password")
ctx.Request.Header.SetMethod("GET")
r := httptest.NewRequest(http.MethodGet, "http://localhost:5001/v1.0/invoke/qcg.default/method/%20cat%20password", nil)
w := httptest.NewRecorder()
handler(http.HandlerFunc(mockedRequestHandler)).ServeHTTP(w, r)
output := new(RouterOutput)
handler(output.handle)(&ctx)
assert.Equal(t, fasthttp.StatusBadRequest, ctx.Response.Header.StatusCode())
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestRequestHandlerWithLegalRouterRule(t *testing.T) {
@ -59,12 +57,9 @@ func TestRequestHandlerWithLegalRouterRule(t *testing.T) {
handler, err := rchecker.GetHandler(meta)
assert.Nil(t, err)
var ctx fasthttp.RequestCtx
ctx.Request.SetHost("localhost:5001")
ctx.Request.SetRequestURI("/v1.0/invoke/qcg.default/method")
ctx.Request.Header.SetMethod("GET")
r := httptest.NewRequest(http.MethodGet, "http://localhost:5001/v1.0/invoke/qcg.default/method", nil)
w := httptest.NewRecorder()
handler(http.HandlerFunc(mockedRequestHandler)).ServeHTTP(w, r)
output := new(RouterOutput)
handler(output.handle)(&ctx)
assert.Equal(t, fasthttp.StatusOK, ctx.Response.Header.StatusCode())
assert.Equal(t, http.StatusOK, w.Code)
}

View File

@ -14,15 +14,16 @@ limitations under the License.
package sentinel
import (
"encoding/json"
"fmt"
"net/http"
sentinel "github.com/alibaba/sentinel-golang/api"
"github.com/alibaba/sentinel-golang/core/base"
"github.com/alibaba/sentinel-golang/core/config"
"github.com/pkg/errors"
"github.com/valyala/fasthttp"
"github.com/dapr/components-contrib/internal/httputils"
mdutils "github.com/dapr/components-contrib/metadata"
"github.com/dapr/components-contrib/middleware"
"github.com/dapr/kit/logger"
)
@ -50,7 +51,7 @@ type Middleware struct {
}
// GetHandler returns the HTTP handler provided by sentinel middleware.
func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.RequestHandler) fasthttp.RequestHandler, error) {
func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(next http.Handler) http.Handler, error) {
var (
meta *middlewareMetadata
err error
@ -72,23 +73,22 @@ func (m *Middleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.R
return nil, err
}
return func(h fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
resourceName := string(ctx.Method()) + ":" + string(ctx.Path())
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
resourceName := r.Method + ":" + r.URL.Path
entry, err := sentinel.Entry(
resourceName,
sentinel.WithResourceType(base.ResTypeWeb),
sentinel.WithTrafficType(base.Inbound),
)
if err != nil {
ctx.Error(fasthttp.StatusMessage(fasthttp.StatusTooManyRequests), fasthttp.StatusTooManyRequests)
httputils.RespondWithError(w, http.StatusTooManyRequests)
return
}
defer entry.Exit()
h(ctx)
}
next.ServeHTTP(w, r)
})
}, nil
}
@ -97,7 +97,6 @@ func (m *Middleware) loadSentinelRules(meta *middlewareMetadata) error {
err := loadRules(meta.FlowRules, newFlowRuleDataSource)
if err != nil {
msg := fmt.Sprintf("fail to load sentinel flow rules: %s", meta.FlowRules)
return errors.Wrap(err, msg)
}
}
@ -106,7 +105,6 @@ func (m *Middleware) loadSentinelRules(meta *middlewareMetadata) error {
err := loadRules(meta.IsolationRules, newIsolationRuleDataSource)
if err != nil {
msg := fmt.Sprintf("fail to load sentinel isolation rules: %s", meta.IsolationRules)
return errors.Wrap(err, msg)
}
}
@ -115,7 +113,6 @@ func (m *Middleware) loadSentinelRules(meta *middlewareMetadata) error {
err := loadRules(meta.CircuitBreakerRules, newCircuitBreakerRuleDataSource)
if err != nil {
msg := fmt.Sprintf("fail to load sentinel circuit breaker rules: %s", meta.CircuitBreakerRules)
return errors.Wrap(err, msg)
}
}
@ -124,7 +121,6 @@ func (m *Middleware) loadSentinelRules(meta *middlewareMetadata) error {
err := loadRules(meta.HotSpotParamRules, newHotSpotParamRuleDataSource)
if err != nil {
msg := fmt.Sprintf("fail to load sentinel hotspot param rules: %s", meta.HotSpotParamRules)
return errors.Wrap(err, msg)
}
}
@ -133,7 +129,6 @@ func (m *Middleware) loadSentinelRules(meta *middlewareMetadata) error {
err := loadRules(meta.SystemRules, newSystemRuleDataSource)
if err != nil {
msg := fmt.Sprintf("fail to load sentinel system rules: %s", meta.SystemRules)
return errors.Wrap(err, msg)
}
}
@ -158,16 +153,10 @@ func (m *Middleware) newSentinelConfig(metadata *middlewareMetadata) *config.Ent
}
func getNativeMetadata(metadata middleware.Metadata) (*middlewareMetadata, error) {
b, err := json.Marshal(metadata.Properties)
if err != nil {
return nil, err
}
var md middlewareMetadata
err = json.Unmarshal(b, &md)
err := mdutils.DecodeMetadata(metadata.Properties, &md)
if err != nil {
return nil, err
}
return &md, nil
}

View File

@ -14,10 +14,11 @@ limitations under the License.
package sentinel
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
"github.com/valyala/fasthttp"
"github.com/dapr/components-contrib/metadata"
"github.com/dapr/components-contrib/middleware"
@ -28,7 +29,7 @@ type counter struct {
count int32
}
func (c *counter) handle(ctx *fasthttp.RequestCtx) {
func (c *counter) handle(w http.ResponseWriter, r *http.Request) {
c.count++
}
@ -50,14 +51,12 @@ func TestRequestHandlerWithFlowRules(t *testing.T) {
handler, err := sentinel.GetHandler(meta)
assert.Nil(t, err)
var ctx fasthttp.RequestCtx
ctx.Request.SetHost("localhost:5001")
ctx.Request.SetRequestURI("/v1.0/nodeapp/healthz")
ctx.Request.Header.SetMethod("GET")
r := httptest.NewRequest(http.MethodGet, "http://localhost:5001/v1.0/nodeapp/healthz", nil)
counter := &counter{}
for i := 0; i < 100; i++ {
handler(counter.handle)(&ctx)
w := httptest.NewRecorder()
handler(http.HandlerFunc(counter.handle)).ServeHTTP(w, r)
}
assert.Equal(t, int32(10), counter.count)

View File

@ -14,8 +14,9 @@ limitations under the License.
package sentinel
import (
"fmt"
"github.com/alibaba/sentinel-golang/ext/datasource"
"github.com/pkg/errors"
)
type propertyDataSource struct {
@ -77,7 +78,7 @@ func (p propertyDataSource) ReadSource() ([]byte, error) {
func (p propertyDataSource) Initialize() error {
src, err := p.ReadSource()
if err != nil {
err = errors.Errorf("Fail to read source, err: %+v", err)
err = fmt.Errorf("fail to read source, err: %w", err)
return err
}

View File

@ -6,15 +6,16 @@ import (
"encoding/json"
"errors"
"fmt"
"net/http"
"os"
"runtime"
"strconv"
"time"
"github.com/valyala/fasthttp"
"github.com/wapc/wapc-go"
"github.com/wapc/wapc-go/engines/wazero"
"github.com/dapr/components-contrib/internal/httputils"
"github.com/dapr/components-contrib/middleware"
"github.com/dapr/kit/logger"
)
@ -69,7 +70,7 @@ func NewMiddleware(logger logger.Logger) middleware.Middleware {
}
// GetHandler returns the HTTP handler provided by wasm basic middleware.
func (m *wapcMiddleware) GetHandler(metadata middleware.Metadata) (func(h fasthttp.RequestHandler) fasthttp.RequestHandler, error) {
func (m *wapcMiddleware) GetHandler(metadata middleware.Metadata) (func(next http.Handler) http.Handler, error) {
rh, err := m.getHandler(metadata)
if err != nil {
return nil, err
@ -148,11 +149,11 @@ type wapcRequestHandler struct {
pool *wapc.Pool
}
func (rh *wapcRequestHandler) requestHandler(h fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
func (rh *wapcRequestHandler) requestHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
instance, err := rh.pool.Get(1 * time.Second)
if err != nil {
ctx.Error("wasm pool busy", fasthttp.StatusInternalServerError)
httputils.RespondWithErrorAndMessage(w, http.StatusInternalServerError, "wasm pool busy")
return
}
defer func() {
@ -161,7 +162,7 @@ func (rh *wapcRequestHandler) requestHandler(h fasthttp.RequestHandler) fasthttp
_ = rh.pool.Return(instance)
}()
err = rh.handle(ctx, instance)
err = rh.handle(r, instance)
if stdout := rh.stdout.String(); len(stdout) > 0 {
rh.logger.Debugf("wasm stdout: %s", stdout)
}
@ -169,22 +170,21 @@ func (rh *wapcRequestHandler) requestHandler(h fasthttp.RequestHandler) fasthttp
rh.logger.Debugf("wasm stderr: %s", stderr)
}
if err != nil {
ctx.Error(err.Error(), fasthttp.StatusInternalServerError)
httputils.RespondWithErrorAndMessage(w, http.StatusInternalServerError, err.Error())
} else {
h(ctx)
next.ServeHTTP(w, r)
}
}
})
}
// handle is like fasthttp.RequestHandler, except it accepts a waPC instance
// and returns an error.
func (rh *wapcRequestHandler) handle(ctx *fasthttp.RequestCtx, instance wapc.Instance) error {
if uri, err := instance.Invoke(ctx, "rewrite", ctx.RequestURI()); err != nil {
// handle is like http.Handler, except it accepts a waPC instance and returns
// an error.
func (rh *wapcRequestHandler) handle(r *http.Request, instance wapc.Instance) error {
if uri, err := instance.Invoke(ctx, "rewrite", []byte(httputils.RequestURI(r))); err != nil {
return err
} else {
ctx.Request.SetRequestURIBytes(uri)
return httputils.SetRequestURI(r, string(uri))
}
return nil
}
// Close implements io.Closer

View File

@ -3,13 +3,15 @@ package basic
import (
"fmt"
"log"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/dapr/components-contrib/internal/httputils"
"github.com/dapr/components-contrib/metadata"
"github.com/stretchr/testify/require"
"github.com/valyala/fasthttp"
"github.com/dapr/components-contrib/middleware"
"github.com/dapr/components-contrib/middleware/http/wasm/basic/internal/test"
@ -165,11 +167,11 @@ func Test_Example(t *testing.T) {
l := test.NewLogger()
handlerFn, err := NewMiddleware(l).GetHandler(middleware.Metadata{Base: meta})
require.NoError(t, err)
handler := handlerFn(func(*fasthttp.RequestCtx) {})
handler := handlerFn(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
var ctx fasthttp.RequestCtx
ctx.Request.SetRequestURI("/v1.0/hi")
handler(&ctx)
require.Equal(t, "/v1.0/hello", string(ctx.RequestURI()))
r := httptest.NewRequest(http.MethodGet, "/v1.0/hi", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, r)
require.Equal(t, "/v1.0/hello", httputils.RequestURI(r))
require.Empty(t, l.(fmt.Stringer).String())
}

View File

@ -3,6 +3,8 @@ package internal_test
import (
"fmt"
"log"
"net/http"
"net/http/httptest"
"os"
"path"
"strconv"
@ -11,7 +13,6 @@ import (
"github.com/dapr/components-contrib/metadata"
"github.com/stretchr/testify/require"
"github.com/valyala/fasthttp"
"github.com/dapr/components-contrib/middleware"
"github.com/dapr/components-contrib/middleware/http/wasm/basic"
@ -43,16 +44,17 @@ func Test_EndToEnd(t *testing.T) {
name string
guest []byte
poolSize int
test func(t *testing.T, handler fasthttp.RequestHandler, log fmt.Stringer)
test func(t *testing.T, handler http.Handler, log fmt.Stringer)
}
tests := []testCase{
{
name: "consoleLog stdout and stderr",
guest: guestWasm[guestWasmOutput],
test: func(t *testing.T, handler fasthttp.RequestHandler, log fmt.Stringer) {
var ctx fasthttp.RequestCtx
handler(&ctx)
test: func(t *testing.T, handler http.Handler, log fmt.Stringer) {
r := httptest.NewRequest(http.MethodGet, "/", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, r)
// First, we expect any console logging written inline from
// init (main) and the request (rewrite) funcs to info level.
@ -74,11 +76,12 @@ request[0] Stderr
name: "multiple requests",
guest: guestWasm[guestWasmOutput],
poolSize: 2,
test: func(t *testing.T, handler fasthttp.RequestHandler, log fmt.Stringer) {
test: func(t *testing.T, handler http.Handler, log fmt.Stringer) {
// Service more requests than the pool size to ensure it works properly.
for i := 0; i < 3; i++ {
var ctx fasthttp.RequestCtx
handler(&ctx)
r := httptest.NewRequest(http.MethodGet, "/", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, r)
}
// We expect to see initialization (main) twice, once for each
@ -110,6 +113,7 @@ Debug(wasm stderr: request[1] Stderr
},
}
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
@ -125,7 +129,7 @@ Debug(wasm stderr: request[1] Stderr
l := test.NewLogger()
handlerFn, err := basic.NewMiddleware(l).GetHandler(middleware.Metadata{Base: meta})
require.NoError(t, err)
tc.test(t, handlerFn(func(*fasthttp.RequestCtx) {}), l.(fmt.Stringer))
tc.test(t, handlerFn(h), l.(fmt.Stringer))
})
}
}

View File

@ -14,10 +14,10 @@ limitations under the License.
package middleware
import (
"github.com/valyala/fasthttp"
"net/http"
)
// Middleware is the interface for a middleware.
type Middleware interface {
GetHandler(metadata Metadata) (func(h fasthttp.RequestHandler) fasthttp.RequestHandler, error)
GetHandler(metadata Metadata) (func(next http.Handler) http.Handler, error)
}

View File

@ -32,6 +32,8 @@ import (
"github.com/Azure/go-autorest/autorest/azure"
azauth "github.com/dapr/components-contrib/internal/authentication/azure"
"github.com/dapr/components-contrib/internal/utils"
contribMetadata "github.com/dapr/components-contrib/metadata"
"github.com/dapr/components-contrib/pubsub"
"github.com/dapr/kit/logger"
"github.com/dapr/kit/retry"
@ -564,6 +566,41 @@ func (aeh *AzureEventHubs) Publish(req *pubsub.PublishRequest) error {
return nil
}
// BulkPublish sends data to Azure Event Hubs in bulk.
func (aeh *AzureEventHubs) BulkPublish(ctx context.Context, req *pubsub.BulkPublishRequest) (pubsub.BulkPublishResponse, error) {
if _, ok := aeh.hubClients[req.Topic]; !ok {
if err := aeh.ensurePublisherClient(ctx, req.Topic); err != nil {
err = fmt.Errorf("error on establishing hub connection: %s", err)
return pubsub.NewBulkPublishResponse(req.Entries, pubsub.PublishFailed, err), err
}
}
// Create a slice of events to send.
events := make([]*eventhub.Event, len(req.Entries))
for i, entry := range req.Entries {
events[i] = &eventhub.Event{Data: entry.Event}
if val, ok := entry.Metadata[partitionKeyMetadataKey]; ok {
events[i].PartitionKey = &val
}
}
// Configure options for sending events.
opts := []eventhub.BatchOption{
eventhub.BatchWithMaxSizeInBytes(utils.GetElemOrDefaultFromMap(
req.Metadata, contribMetadata.MaxBulkPubBytesKey, int(eventhub.DefaultMaxMessageSizeInBytes))),
}
// Send events.
err := aeh.hubClients[req.Topic].SendBatch(ctx, eventhub.NewEventBatchIterator(events...), opts...)
if err != nil {
// Partial success is not supported by Azure Event Hubs.
// If an error occurs, all events are considered failed.
return pubsub.NewBulkPublishResponse(req.Entries, pubsub.PublishFailed, err), err
}
return pubsub.NewBulkPublishResponse(req.Entries, pubsub.PublishSucceeded, nil), nil
}
// Subscribe receives data from Azure Event Hubs.
func (aeh *AzureEventHubs) Subscribe(subscribeCtx context.Context, req pubsub.SubscribeRequest, handler pubsub.Handler) error {
err := aeh.validateSubscriptionAttributes()

View File

@ -21,6 +21,7 @@ import (
"time"
azservicebus "github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus"
"github.com/google/uuid"
contribMetadata "github.com/dapr/components-contrib/metadata"
"github.com/dapr/components-contrib/pubsub"
@ -76,66 +77,87 @@ const (
func NewPubsubMessageFromASBMessage(asbMsg *azservicebus.ReceivedMessage, topic string) (*pubsub.NewMessage, error) {
pubsubMsg := &pubsub.NewMessage{
Topic: topic,
Data: asbMsg.Body,
}
pubsubMsg.Data = asbMsg.Body
pubsubMsg.Metadata = addMessageAttributesToMetadata(pubsubMsg.Metadata, asbMsg)
addToMetadata := func(msg *pubsub.NewMessage, key, value string) {
if msg.Metadata == nil {
msg.Metadata = make(map[string]string)
}
return pubsubMsg, nil
}
msg.Metadata[fmt.Sprintf("metadata.%s", key)] = value
func NewBulkMessageEntryFromASBMessage(asbMsg *azservicebus.ReceivedMessage) (pubsub.BulkMessageEntry, error) {
entryId, err := uuid.NewRandom() //nolint:stylecheck
if err != nil {
return pubsub.BulkMessageEntry{}, err
}
bulkMsgEntry := pubsub.BulkMessageEntry{
EntryId: entryId.String(),
Event: asbMsg.Body,
}
bulkMsgEntry.Metadata = addMessageAttributesToMetadata(bulkMsgEntry.Metadata, asbMsg)
return bulkMsgEntry, nil
}
func addMessageAttributesToMetadata(metadata map[string]string, asbMsg *azservicebus.ReceivedMessage) map[string]string {
if metadata == nil {
metadata = map[string]string{}
}
addToMetadata := func(metadata map[string]string, key, value string) {
metadata["metadata."+key] = value
}
if asbMsg.MessageID != "" {
addToMetadata(pubsubMsg, MessageIDMetadataKey, asbMsg.MessageID)
addToMetadata(metadata, MessageIDMetadataKey, asbMsg.MessageID)
}
if asbMsg.SessionID != nil {
addToMetadata(pubsubMsg, SessionIDMetadataKey, *asbMsg.SessionID)
addToMetadata(metadata, SessionIDMetadataKey, *asbMsg.SessionID)
}
if asbMsg.CorrelationID != nil && *asbMsg.CorrelationID != "" {
addToMetadata(pubsubMsg, CorrelationIDMetadataKey, *asbMsg.CorrelationID)
addToMetadata(metadata, CorrelationIDMetadataKey, *asbMsg.CorrelationID)
}
if asbMsg.Subject != nil && *asbMsg.Subject != "" {
addToMetadata(pubsubMsg, LabelMetadataKey, *asbMsg.Subject)
addToMetadata(metadata, LabelMetadataKey, *asbMsg.Subject)
}
if asbMsg.ReplyTo != nil && *asbMsg.ReplyTo != "" {
addToMetadata(pubsubMsg, ReplyToMetadataKey, *asbMsg.ReplyTo)
addToMetadata(metadata, ReplyToMetadataKey, *asbMsg.ReplyTo)
}
if asbMsg.To != nil && *asbMsg.To != "" {
addToMetadata(pubsubMsg, ToMetadataKey, *asbMsg.To)
addToMetadata(metadata, ToMetadataKey, *asbMsg.To)
}
if asbMsg.ContentType != nil && *asbMsg.ContentType != "" {
addToMetadata(pubsubMsg, ContentTypeMetadataKey, *asbMsg.ContentType)
addToMetadata(metadata, ContentTypeMetadataKey, *asbMsg.ContentType)
}
if asbMsg.LockToken != [16]byte{} {
addToMetadata(pubsubMsg, LockTokenMetadataKey, base64.StdEncoding.EncodeToString(asbMsg.LockToken[:]))
addToMetadata(metadata, LockTokenMetadataKey, base64.StdEncoding.EncodeToString(asbMsg.LockToken[:]))
}
// Always set delivery count.
addToMetadata(pubsubMsg, DeliveryCountMetadataKey, strconv.FormatInt(int64(asbMsg.DeliveryCount), 10))
addToMetadata(metadata, DeliveryCountMetadataKey, strconv.FormatInt(int64(asbMsg.DeliveryCount), 10))
if asbMsg.EnqueuedTime != nil {
// Preserve RFC2616 time format.
addToMetadata(pubsubMsg, EnqueuedTimeUtcMetadataKey, asbMsg.EnqueuedTime.UTC().Format(http.TimeFormat))
addToMetadata(metadata, EnqueuedTimeUtcMetadataKey, asbMsg.EnqueuedTime.UTC().Format(http.TimeFormat))
}
if asbMsg.SequenceNumber != nil {
addToMetadata(pubsubMsg, SequenceNumberMetadataKey, strconv.FormatInt(*asbMsg.SequenceNumber, 10))
addToMetadata(metadata, SequenceNumberMetadataKey, strconv.FormatInt(*asbMsg.SequenceNumber, 10))
}
if asbMsg.ScheduledEnqueueTime != nil {
// Preserve RFC2616 time format.
addToMetadata(pubsubMsg, ScheduledEnqueueTimeUtcMetadataKey, asbMsg.ScheduledEnqueueTime.UTC().Format(http.TimeFormat))
addToMetadata(metadata, ScheduledEnqueueTimeUtcMetadataKey, asbMsg.ScheduledEnqueueTime.UTC().Format(http.TimeFormat))
}
if asbMsg.PartitionKey != nil {
addToMetadata(pubsubMsg, PartitionKeyMetadataKey, *asbMsg.PartitionKey)
addToMetadata(metadata, PartitionKeyMetadataKey, *asbMsg.PartitionKey)
}
if asbMsg.LockedUntil != nil {
// Preserve RFC2616 time format.
addToMetadata(pubsubMsg, LockedUntilUtcMetadataKey, asbMsg.LockedUntil.UTC().Format(http.TimeFormat))
addToMetadata(metadata, LockedUntilUtcMetadataKey, asbMsg.LockedUntil.UTC().Format(http.TimeFormat))
}
return pubsubMsg, nil
return metadata
}
// NewASBMessageFromPubsubRequest builds a new Azure Service Bus message from a PublishRequest.
@ -144,64 +166,98 @@ func NewASBMessageFromPubsubRequest(req *pubsub.PublishRequest) (*azservicebus.M
Body: req.Data,
}
err := addMetadataToMessage(asbMsg, req.Metadata)
return asbMsg, err
}
// NewASBMessageFromBulkMessageEntry builds a new Azure Service Bus message from a BulkMessageEntry.
func NewASBMessageFromBulkMessageEntry(entry pubsub.BulkMessageEntry) (*azservicebus.Message, error) {
asbMsg := &azservicebus.Message{
Body: entry.Event,
ContentType: &entry.ContentType,
}
err := addMetadataToMessage(asbMsg, entry.Metadata)
return asbMsg, err
}
func addMetadataToMessage(asbMsg *azservicebus.Message, metadata map[string]string) error {
// Common properties.
ttl, ok, _ := contribMetadata.TryGetTTL(req.Metadata)
ttl, ok, _ := contribMetadata.TryGetTTL(metadata)
if ok {
asbMsg.TimeToLive = &ttl
}
// Azure Service Bus specific properties.
// reference: https://docs.microsoft.com/en-us/rest/api/servicebus/message-headers-and-properties#message-headers
msgID, ok, _ := tryGetString(req.Metadata, MessageIDMetadataKey)
msgID, ok, _ := tryGetString(metadata, MessageIDMetadataKey)
if ok {
asbMsg.MessageID = &msgID
}
correlationID, ok, _ := tryGetString(req.Metadata, CorrelationIDMetadataKey)
correlationID, ok, _ := tryGetString(metadata, CorrelationIDMetadataKey)
if ok {
asbMsg.CorrelationID = &correlationID
}
sessionID, okSessionID, _ := tryGetString(req.Metadata, SessionIDMetadataKey)
sessionID, okSessionID, _ := tryGetString(metadata, SessionIDMetadataKey)
if okSessionID {
asbMsg.SessionID = &sessionID
}
label, ok, _ := tryGetString(req.Metadata, LabelMetadataKey)
label, ok, _ := tryGetString(metadata, LabelMetadataKey)
if ok {
asbMsg.Subject = &label
}
replyTo, ok, _ := tryGetString(req.Metadata, ReplyToMetadataKey)
replyTo, ok, _ := tryGetString(metadata, ReplyToMetadataKey)
if ok {
asbMsg.ReplyTo = &replyTo
}
to, ok, _ := tryGetString(req.Metadata, ToMetadataKey)
to, ok, _ := tryGetString(metadata, ToMetadataKey)
if ok {
asbMsg.To = &to
}
partitionKey, ok, _ := tryGetString(req.Metadata, PartitionKeyMetadataKey)
partitionKey, ok, _ := tryGetString(metadata, PartitionKeyMetadataKey)
if ok {
if okSessionID && partitionKey != sessionID {
return nil, fmt.Errorf("session id %s and partition key %s should be equal when both present", sessionID, partitionKey)
return fmt.Errorf("session id %s and partition key %s should be equal when both present", sessionID, partitionKey)
}
asbMsg.PartitionKey = &partitionKey
}
contentType, ok, _ := tryGetString(req.Metadata, ContentTypeMetadataKey)
contentType, ok, _ := tryGetString(metadata, ContentTypeMetadataKey)
if ok {
asbMsg.ContentType = &contentType
}
scheduledEnqueueTime, ok, _ := tryGetScheduledEnqueueTime(req.Metadata)
scheduledEnqueueTime, ok, _ := tryGetScheduledEnqueueTime(metadata)
if ok {
asbMsg.ScheduledEnqueueTime = scheduledEnqueueTime
}
return asbMsg, nil
return nil
}
// UpdateASBBatchMessageWithBulkPublishRequest updates the batch message with messages from the bulk publish request.
func UpdateASBBatchMessageWithBulkPublishRequest(asbMsgBatch *azservicebus.MessageBatch, req *pubsub.BulkPublishRequest) error {
// Add entries from bulk request to batch.
for _, entry := range req.Entries {
asbMsg, err := NewASBMessageFromBulkMessageEntry(entry)
if err != nil {
return err
}
err = asbMsgBatch.AddMessage(asbMsg, nil)
if err != nil {
return err
}
}
return nil
}
func tryGetString(props map[string]string, key string) (string, bool, error) {

View File

@ -14,6 +14,7 @@ limitations under the License.
package servicebus
import (
"fmt"
"net/http"
"testing"
"time"
@ -21,48 +22,107 @@ import (
azservicebus "github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/dapr/components-contrib/pubsub"
)
func TestNewASBMessageFromPubsubRequest(t *testing.T) {
testMessageData := []byte("test message")
testMessageID := "testMessageId"
testCorrelationID := "testCorrelationId"
testSessionID := "testSessionId"
testLabel := "testLabel"
testReplyTo := "testReplyTo"
testTo := "testTo"
testPartitionKey := testSessionID
testPartitionKeyUnique := "testPartitionKey"
testContentType := "testContentType"
nowUtc := time.Now().UTC()
testScheduledEnqueueTimeUtc := nowUtc.Format(http.TimeFormat)
var (
testMessageID = "testMessageId"
testCorrelationID = "testCorrelationId"
testSessionID = "testSessionId"
testLabel = "testLabel"
testReplyTo = "testReplyTo"
testTo = "testTo"
testPartitionKey = testSessionID
testPartitionKeyUnique = "testPartitionKey"
testContentType = "testContentType"
nowUtc = time.Now().UTC()
testScheduledEnqueueTimeUtc = nowUtc.Format(http.TimeFormat)
testLockTokenString = "bG9ja3Rva2VuAAAAAAAAAA==" //nolint:gosec
testLockTokenBytes = [16]byte{108, 111, 99, 107, 116, 111, 107, 101, 110}
testDeliveryCount uint32 = 1
testSampleTime = time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC)
testSampleTimeHTTPFormat = "Thu, 01 Jan 1970 00:00:00 GMT"
testSequenceNumber int64 = 1
)
func TestAddMessageAttributesToMetadata(t *testing.T) {
testCases := []struct {
name string
ASBMessage azservicebus.ReceivedMessage
expectedMetadata map[string]string
}{
{
name: "Metadata must contain all attributes with the correct prefix",
ASBMessage: azservicebus.ReceivedMessage{
MessageID: testMessageID,
SessionID: &testSessionID,
CorrelationID: &testCorrelationID,
Subject: &testLabel,
ReplyTo: &testReplyTo,
To: &testTo,
ContentType: &testContentType,
LockToken: testLockTokenBytes,
DeliveryCount: testDeliveryCount,
EnqueuedTime: &testSampleTime,
SequenceNumber: &testSequenceNumber,
ScheduledEnqueueTime: &testSampleTime,
PartitionKey: &testPartitionKey,
LockedUntil: &testSampleTime,
},
expectedMetadata: map[string]string{
"metadata." + MessageIDMetadataKey: testMessageID,
"metadata." + SessionIDMetadataKey: testSessionID,
"metadata." + CorrelationIDMetadataKey: testCorrelationID,
"metadata." + LabelMetadataKey: testLabel, // Subject
"metadata." + ReplyToMetadataKey: testReplyTo,
"metadata." + ToMetadataKey: testTo,
"metadata." + ContentTypeMetadataKey: testContentType,
"metadata." + LockTokenMetadataKey: testLockTokenString,
"metadata." + DeliveryCountMetadataKey: "1",
"metadata." + EnqueuedTimeUtcMetadataKey: testSampleTimeHTTPFormat,
"metadata." + SequenceNumberMetadataKey: "1",
"metadata." + ScheduledEnqueueTimeUtcMetadataKey: testSampleTimeHTTPFormat,
"metadata." + PartitionKeyMetadataKey: testPartitionKey,
"metadata." + LockedUntilUtcMetadataKey: testSampleTimeHTTPFormat,
},
},
}
metadataMap := map[string]map[string]string{
"Nil": nil,
"Empty": {},
}
for _, tc := range testCases {
for mType, mMap := range metadataMap {
t.Run(fmt.Sprintf("%s, metadata is %s", tc.name, mType), func(t *testing.T) {
actual := addMessageAttributesToMetadata(mMap, &tc.ASBMessage)
assert.Equal(t, tc.expectedMetadata, actual)
})
}
}
}
func TestAddMetadataToMessage(t *testing.T) {
testCases := []struct {
name string
pubsubRequest pubsub.PublishRequest
metadata map[string]string
expectedAzServiceBusMessage azservicebus.Message
expectError bool
}{
{
name: "Maps pubsub request to azure service bus message.",
pubsubRequest: pubsub.PublishRequest{
Data: testMessageData,
Metadata: map[string]string{
MessageIDMetadataKey: testMessageID,
CorrelationIDMetadataKey: testCorrelationID,
SessionIDMetadataKey: testSessionID,
LabelMetadataKey: testLabel,
ReplyToMetadataKey: testReplyTo,
ToMetadataKey: testTo,
PartitionKeyMetadataKey: testPartitionKey,
ContentTypeMetadataKey: testContentType,
ScheduledEnqueueTimeUtcMetadataKey: testScheduledEnqueueTimeUtc,
},
metadata: map[string]string{
MessageIDMetadataKey: testMessageID,
CorrelationIDMetadataKey: testCorrelationID,
SessionIDMetadataKey: testSessionID,
LabelMetadataKey: testLabel,
ReplyToMetadataKey: testReplyTo,
ToMetadataKey: testTo,
PartitionKeyMetadataKey: testPartitionKey,
ContentTypeMetadataKey: testContentType,
ScheduledEnqueueTimeUtcMetadataKey: testScheduledEnqueueTimeUtc,
},
expectedAzServiceBusMessage: azservicebus.Message{
Body: testMessageData,
MessageID: &testMessageID,
CorrelationID: &testCorrelationID,
SessionID: &testSessionID,
@ -77,21 +137,17 @@ func TestNewASBMessageFromPubsubRequest(t *testing.T) {
},
{
name: "Errors when partition key and session id set but not equal.",
pubsubRequest: pubsub.PublishRequest{
Data: testMessageData,
Metadata: map[string]string{
MessageIDMetadataKey: testMessageID,
CorrelationIDMetadataKey: testCorrelationID,
SessionIDMetadataKey: testSessionID,
LabelMetadataKey: testLabel,
ReplyToMetadataKey: testReplyTo,
ToMetadataKey: testTo,
PartitionKeyMetadataKey: testPartitionKeyUnique,
ContentTypeMetadataKey: testContentType,
},
metadata: map[string]string{
MessageIDMetadataKey: testMessageID,
CorrelationIDMetadataKey: testCorrelationID,
SessionIDMetadataKey: testSessionID,
LabelMetadataKey: testLabel,
ReplyToMetadataKey: testReplyTo,
ToMetadataKey: testTo,
PartitionKeyMetadataKey: testPartitionKeyUnique,
ContentTypeMetadataKey: testContentType,
},
expectedAzServiceBusMessage: azservicebus.Message{
Body: testMessageData,
MessageID: &testMessageID,
CorrelationID: &testCorrelationID,
SessionID: &testSessionID,
@ -108,7 +164,8 @@ func TestNewASBMessageFromPubsubRequest(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// act.
msg, err := NewASBMessageFromPubsubRequest(&tc.pubsubRequest)
msg := &azservicebus.Message{}
err := addMetadataToMessage(msg, tc.metadata)
// assert.
if tc.expectError {

View File

@ -30,6 +30,7 @@ import (
azauth "github.com/dapr/components-contrib/internal/authentication/azure"
impl "github.com/dapr/components-contrib/internal/component/azure/servicebus"
"github.com/dapr/components-contrib/internal/utils"
contribMetadata "github.com/dapr/components-contrib/metadata"
"github.com/dapr/components-contrib/pubsub"
"github.com/dapr/kit/logger"
@ -37,7 +38,9 @@ import (
)
const (
errorMessagePrefix = "azure service bus error:"
errorMessagePrefix = "azure service bus error:"
defaultMaxBulkSubCount = 100
defaultMaxBulkPubBytes uint64 = 1024 * 128 // 128 KiB
)
var retriableSendingErrors = map[amqp.ErrorCondition]struct{}{
@ -363,7 +366,97 @@ func (a *azureServiceBus) Publish(req *pubsub.PublishRequest) error {
)
}
func (a *azureServiceBus) BulkPublish(ctx context.Context, req *pubsub.BulkPublishRequest) (pubsub.BulkPublishResponse, error) {
// If the request is empty, sender.SendMessageBatch will panic later.
// Return an empty response to avoid this.
if len(req.Entries) == 0 {
a.logger.Warnf("Empty bulk publish request, skipping")
return pubsub.NewBulkPublishResponse(req.Entries, pubsub.PublishSucceeded, nil), nil
}
sender, err := a.senderForTopic(ctx, req.Topic)
if err != nil {
return pubsub.NewBulkPublishResponse(req.Entries, pubsub.PublishFailed, err), err
}
// Create a new batch of messages with batch options.
batchOpts := &servicebus.MessageBatchOptions{
MaxBytes: utils.GetElemOrDefaultFromMap(req.Metadata, contribMetadata.MaxBulkPubBytesKey, defaultMaxBulkPubBytes),
}
batchMsg, err := sender.NewMessageBatch(ctx, batchOpts)
if err != nil {
return pubsub.NewBulkPublishResponse(req.Entries, pubsub.PublishFailed, err), err
}
// Add messages from the bulk publish request to the batch.
err = UpdateASBBatchMessageWithBulkPublishRequest(batchMsg, req)
if err != nil {
return pubsub.NewBulkPublishResponse(req.Entries, pubsub.PublishFailed, err), err
}
// Azure Service Bus does not return individual status for each message in the request.
err = sender.SendMessageBatch(ctx, batchMsg, nil)
if err != nil {
return pubsub.NewBulkPublishResponse(req.Entries, pubsub.PublishFailed, err), err
}
return pubsub.NewBulkPublishResponse(req.Entries, pubsub.PublishSucceeded, nil), nil
}
func (a *azureServiceBus) Subscribe(subscribeCtx context.Context, req pubsub.SubscribeRequest, handler pubsub.Handler) error {
sub := impl.NewSubscription(
subscribeCtx,
a.metadata.MaxActiveMessages,
a.metadata.TimeoutInSec,
a.metadata.MaxRetriableErrorsPerSec,
a.metadata.MaxConcurrentHandlers,
"topic "+req.Topic,
a.logger,
)
receiveAndBlockFn := func(onFirstSuccess func()) error {
return sub.ReceiveAndBlock(
a.getHandlerFunc(req.Topic, handler),
a.metadata.LockRenewalInSec,
false, // Bulk is not supported in regular Subscribe.
onFirstSuccess,
)
}
return a.doSubscribe(subscribeCtx, req, sub, receiveAndBlockFn)
}
func (a *azureServiceBus) BulkSubscribe(subscribeCtx context.Context, req pubsub.SubscribeRequest, handler pubsub.BulkHandler) error {
maxBulkSubCount := utils.GetElemOrDefaultFromMap(req.Metadata, contribMetadata.MaxBulkSubCountKey, defaultMaxBulkSubCount)
sub := impl.NewBulkSubscription(
subscribeCtx,
a.metadata.MaxActiveMessages,
a.metadata.TimeoutInSec,
maxBulkSubCount,
a.metadata.MaxRetriableErrorsPerSec,
a.metadata.MaxConcurrentHandlers,
"topic "+req.Topic,
a.logger,
)
receiveAndBlockFn := func(onFirstSuccess func()) error {
return sub.ReceiveAndBlock(
a.getBulkHandlerFunc(req.Topic, handler),
a.metadata.LockRenewalInSec,
true, // Bulk is supported in BulkSubscribe.
onFirstSuccess,
)
}
return a.doSubscribe(subscribeCtx, req, sub, receiveAndBlockFn)
}
// doSubscribe is a helper function that handles the common logic for both Subscribe and BulkSubscribe.
// The receiveAndBlockFn is a function should invoke a blocking call to receive messages from the topic.
func (a *azureServiceBus) doSubscribe(subscribeCtx context.Context,
req pubsub.SubscribeRequest, sub *impl.Subscription, receiveAndBlockFn func(func()) error,
) error {
subID := a.metadata.ConsumerID
if !a.metadata.DisableEntityManagement {
err := a.ensureSubscription(subscribeCtx, subID, req.Topic)
@ -378,19 +471,14 @@ func (a *azureServiceBus) Subscribe(subscribeCtx context.Context, req pubsub.Sub
bo.InitialInterval = time.Duration(a.metadata.MinConnectionRecoveryInSec) * time.Second
bo.MaxInterval = time.Duration(a.metadata.MaxConnectionRecoveryInSec) * time.Second
onFirstSuccess := func() {
// Reset the backoff when the subscription is successful and we have received the first message
bo.Reset()
}
go func() {
// Reconnect loop.
for {
sub := impl.NewSubscription(
subscribeCtx,
a.metadata.MaxActiveMessages,
a.metadata.TimeoutInSec,
a.metadata.MaxRetriableErrorsPerSec,
a.metadata.MaxConcurrentHandlers,
"topic "+req.Topic,
a.logger,
)
// Blocks until a successful connection (or until context is canceled)
err := sub.Connect(func() (*servicebus.Receiver, error) {
return a.client.NewReceiverForSubscription(req.Topic, subID, nil)
@ -403,16 +491,9 @@ func (a *azureServiceBus) Subscribe(subscribeCtx context.Context, req pubsub.Sub
return
}
// ReceiveAndBlock will only return with an error that it cannot handle internally. The subscription connection is closed when this method returns.
// receiveAndBlockFn will only return with an error that it cannot handle internally. The subscription connection is closed when this method returns.
// If that occurs, we will log the error and attempt to re-establish the subscription connection until we exhaust the number of reconnect attempts.
err = sub.ReceiveAndBlock(
a.getHandlerFunc(req.Topic, handler),
a.metadata.LockRenewalInSec,
func() {
// Reset the backoff when the subscription is successful and we have received the first message
bo.Reset()
},
)
err = receiveAndBlockFn(onFirstSuccess)
if err != nil {
var detachError *amqp.DetachError
var amqpError *amqp.Error
@ -446,16 +527,58 @@ func (a *azureServiceBus) Subscribe(subscribeCtx context.Context, req pubsub.Sub
}
func (a *azureServiceBus) getHandlerFunc(topic string, handler pubsub.Handler) impl.HandlerFunc {
return func(ctx context.Context, asbMsg *servicebus.ReceivedMessage) error {
pubsubMsg, err := NewPubsubMessageFromASBMessage(asbMsg, topic)
emptyResponseItems := []impl.HandlerResponseItem{}
// Only the first ASB message is used in the actual handler invocation.
return func(ctx context.Context, asbMsgs []*servicebus.ReceivedMessage) ([]impl.HandlerResponseItem, error) {
if len(asbMsgs) != 1 {
return nil, fmt.Errorf("expected 1 message, got %d", len(asbMsgs))
}
pubsubMsg, err := NewPubsubMessageFromASBMessage(asbMsgs[0], topic)
if err != nil {
return fmt.Errorf("failed to get pubsub message from azure service bus message: %+v", err)
return emptyResponseItems, fmt.Errorf("failed to get pubsub message from azure service bus message: %+v", err)
}
handleCtx, handleCancel := context.WithTimeout(ctx, time.Duration(a.metadata.HandlerTimeoutInSec)*time.Second)
defer handleCancel()
a.logger.Debugf("Calling app's handler for message %s on topic %s", asbMsg.MessageID, topic)
return handler(handleCtx, pubsubMsg)
a.logger.Debugf("Calling app's handler for message %s on topic %s", asbMsgs[0].MessageID, topic)
return emptyResponseItems, handler(handleCtx, pubsubMsg)
}
}
func (a *azureServiceBus) getBulkHandlerFunc(topic string, handler pubsub.BulkHandler) impl.HandlerFunc {
return func(ctx context.Context, asbMsgs []*servicebus.ReceivedMessage) ([]impl.HandlerResponseItem, error) {
pubsubMsgs := make([]pubsub.BulkMessageEntry, len(asbMsgs))
for i, asbMsg := range asbMsgs {
pubsubMsg, err := NewBulkMessageEntryFromASBMessage(asbMsg)
if err != nil {
return nil, fmt.Errorf("failed to get pubsub message from azure service bus message: %+v", err)
}
pubsubMsgs[i] = pubsubMsg
}
// Note, no metadata is currently supported here.
// In the future, we could add propagate metadata to the handler if required.
bulkMessage := &pubsub.BulkMessage{
Entries: pubsubMsgs,
Metadata: map[string]string{},
Topic: topic,
}
handleCtx, handleCancel := context.WithTimeout(ctx, time.Duration(a.metadata.HandlerTimeoutInSec)*time.Second)
defer handleCancel()
a.logger.Debugf("Calling app's handler for %d messages on topic %s", len(asbMsgs), topic)
resps, err := handler(handleCtx, bulkMessage)
implResps := make([]impl.HandlerResponseItem, len(resps))
for i, resp := range resps {
implResps[i] = impl.HandlerResponseItem{
EntryId: resp.EntryId,
Error: resp.Error,
}
}
return implResps, err
}
}

View File

@ -29,6 +29,8 @@ import (
const (
// DefaultCloudEventType is the default event type for an Dapr published event.
DefaultCloudEventType = "com.dapr.event.sent"
// DefaultBulkEventType is the default bulk event type for a Dapr published event.
DefaultBulkEventType = "com.dapr.event.sent.bulk"
// CloudEventsSpecVersion is the specversion used by Dapr for the cloud events implementation.
CloudEventsSpecVersion = "1.0"
// DefaultCloudEventSource is the default event source.

View File

@ -19,6 +19,8 @@ import (
"github.com/dapr/kit/logger"
"github.com/dapr/components-contrib/internal/component/kafka"
"github.com/dapr/components-contrib/metadata"
"github.com/dapr/components-contrib/pubsub"
)
@ -36,7 +38,32 @@ func (p *PubSub) Init(metadata pubsub.Metadata) error {
}
func (p *PubSub) Subscribe(ctx context.Context, req pubsub.SubscribeRequest, handler pubsub.Handler) error {
p.kafka.AddTopicHandler(req.Topic, adaptHandler(handler))
handlerConfig := kafka.SubscriptionHandlerConfig{
IsBulkSubscribe: false,
Handler: adaptHandler(handler),
}
return p.subscribeUtil(ctx, req, handlerConfig)
}
func (p *PubSub) BulkSubscribe(ctx context.Context, req pubsub.SubscribeRequest,
handler pubsub.BulkHandler,
) error {
subConfig := pubsub.BulkSubscribeConfig{
MaxBulkSubCount: kafka.GetIntFromMetadata(req.Metadata, metadata.MaxBulkSubCountKey,
kafka.DefaultMaxBulkSubCount),
MaxBulkSubAwaitDurationMs: kafka.GetIntFromMetadata(req.Metadata,
metadata.MaxBulkSubAwaitDurationMsKey, kafka.DefaultMaxBulkSubAwaitDurationMs),
}
handlerConfig := kafka.SubscriptionHandlerConfig{
IsBulkSubscribe: true,
SubscribeConfig: subConfig,
BulkHandler: adaptBulkHandler(handler),
}
return p.subscribeUtil(ctx, req, handlerConfig)
}
func (p *PubSub) subscribeUtil(ctx context.Context, req pubsub.SubscribeRequest, handlerConfig kafka.SubscriptionHandlerConfig) error {
p.kafka.AddTopicHandler(req.Topic, handlerConfig)
go func() {
// Wait for context cancelation
@ -78,6 +105,11 @@ func (p *PubSub) Publish(req *pubsub.PublishRequest) error {
return p.kafka.Publish(req.Topic, req.Data, req.Metadata)
}
// BatchPublish messages to Kafka cluster.
func (p *PubSub) BulkPublish(ctx context.Context, req *pubsub.BulkPublishRequest) (pubsub.BulkPublishResponse, error) {
return p.kafka.BulkPublish(ctx, req.Topic, req.Entries, req.Metadata)
}
func (p *PubSub) Close() (err error) {
p.subscribeCancel()
return p.kafka.Close()
@ -97,3 +129,24 @@ func adaptHandler(handler pubsub.Handler) kafka.EventHandler {
})
}
}
func adaptBulkHandler(handler pubsub.BulkHandler) kafka.BulkEventHandler {
return func(ctx context.Context, event *kafka.KafkaBulkMessage) ([]pubsub.BulkSubscribeResponseEntry, error) {
messages := make([]pubsub.BulkMessageEntry, 0)
for _, leafEvent := range event.Entries {
message := pubsub.BulkMessageEntry{
EntryId: leafEvent.EntryId,
Event: leafEvent.Event,
Metadata: leafEvent.Metadata,
ContentType: leafEvent.ContentType,
}
messages = append(messages, message)
}
return handler(ctx, &pubsub.BulkMessage{
Topic: event.Topic,
Entries: messages,
Metadata: event.Metadata,
})
}
}

View File

@ -29,9 +29,40 @@ type PubSub interface {
Close() error
}
// BulkPublisher is the interface that wraps the BulkPublish method.
// BulkPublish publishes a collection of entries/messages in a BulkPublishRequest to a
// message bus topic and returns a BulkPublishResponse with individual statuses for each message.
type BulkPublisher interface {
BulkPublish(ctx context.Context, req *BulkPublishRequest) (BulkPublishResponse, error)
}
// BulkSubscriber is the interface defining BulkSubscribe definition for message buses
type BulkSubscriber interface {
// BulkSubscribe is used to subscribe to a topic and receive collection of entries/ messages
// from a message bus topic.
// The bulkHandler will be called with a list of messages.
BulkSubscribe(ctx context.Context, req SubscribeRequest, bulkHandler BulkHandler) error
}
// Handler is the handler used to invoke the app handler.
type Handler func(ctx context.Context, msg *NewMessage) error
// BulkHandler is the handler used to invoke the app handler in a bulk fashion.
// If second return type error is not nil, and []BulkSubscribeResponseEntry is nil,
// it represents some issue and that none of the message could be sent.
// If second return type error is not nil, and []BulkSubscribeResponseEntry is also not nil,
// []BulkSubscribeResponseEntry can be checked for each message's response status.
// If second return type error is nil, that reflects all items were sent successfully
// and []BulkSubscribeResponseEntry doesn't matter
// []BulkSubscribeResponseEntry represents individual statuses for each message in an
// orderly fashion.
type BulkHandler func(ctx context.Context, msg *BulkMessage) ([]BulkSubscribeResponseEntry, error)
func Ping(pubsub PubSub) error {
// checks if this pubsub has the ping option then executes
if pubsubWithPing, ok := pubsub.(health.Pinger); ok {

View File

@ -66,8 +66,8 @@ type rabbitMQ struct {
// interface used to allow unit testing.
type rabbitMQChannelBroker interface {
Publish(exchange string, key string, mandatory bool, immediate bool, msg amqp.Publishing) error
PublishWithDeferredConfirm(exchange string, key string, mandatory bool, immediate bool, msg amqp.Publishing) (*amqp.DeferredConfirmation, error)
PublishWithContext(ctx context.Context, exchange string, key string, mandatory bool, immediate bool, msg amqp.Publishing) error
PublishWithDeferredConfirmWithContext(ctx context.Context, exchange string, key string, mandatory bool, immediate bool, msg amqp.Publishing) (*amqp.DeferredConfirmation, error)
QueueDeclare(name string, durable bool, autoDelete bool, exclusive bool, noWait bool, args amqp.Table) (amqp.Queue, error)
QueueBind(name string, key string, exchange string, noWait bool, args amqp.Table) error
Consume(queue string, consumer string, autoAck bool, exclusive bool, noLocal bool, noWait bool, args amqp.Table) (<-chan amqp.Delivery, error)
@ -190,7 +190,7 @@ func (r *rabbitMQ) publishSync(req *pubsub.PublishRequest) (rabbitMQChannelBroke
routingKey = val
}
confirm, err := r.channel.PublishWithDeferredConfirm(req.Topic, routingKey, false, false, amqp.Publishing{
confirm, err := r.channel.PublishWithDeferredConfirmWithContext(r.ctx, req.Topic, routingKey, false, false, amqp.Publishing{
ContentType: "text/plain",
Body: req.Data,
DeliveryMode: r.metadata.deliveryMode,

View File

@ -341,13 +341,13 @@ func (r *rabbitMQInMemoryBroker) Qos(prefetchCount, prefetchSize int, global boo
return nil
}
func (r *rabbitMQInMemoryBroker) Publish(exchange string, key string, mandatory bool, immediate bool, msg amqp.Publishing) error {
func (r *rabbitMQInMemoryBroker) PublishWithContext(ctx context.Context, exchange string, key string, mandatory bool, immediate bool, msg amqp.Publishing) error {
// This is actually how the SDK implements it
_, err := r.PublishWithDeferredConfirm(exchange, key, mandatory, immediate, msg)
_, err := r.PublishWithDeferredConfirmWithContext(ctx, exchange, key, mandatory, immediate, msg)
return err
}
func (r *rabbitMQInMemoryBroker) PublishWithDeferredConfirm(exchange string, key string, mandatory bool, immediate bool, msg amqp.Publishing) (*amqp.DeferredConfirmation, error) {
func (r *rabbitMQInMemoryBroker) PublishWithDeferredConfirmWithContext(ctx context.Context, exchange string, key string, mandatory bool, immediate bool, msg amqp.Publishing) (*amqp.DeferredConfirmation, error) {
if string(msg.Body) == errorChannelConnection {
return nil, errors.New(errorChannelConnection)
}

View File

@ -22,6 +22,14 @@ type PublishRequest struct {
ContentType *string `json:"contentType,omitempty"`
}
// BulkPublishRequest is the request to publish mutilple messages.
type BulkPublishRequest struct {
Entries []BulkMessageEntry `json:"entries"`
PubsubName string `json:"pubsubname"`
Topic string `json:"topic"`
Metadata map[string]string `json:"metadata"`
}
// SubscribeRequest is the request to subscribe to a topic.
type SubscribeRequest struct {
Topic string `json:"topic"`
@ -35,3 +43,26 @@ type NewMessage struct {
Metadata map[string]string `json:"metadata"`
ContentType *string `json:"contentType,omitempty"`
}
// BulkMessage represents bulk message arriving from a message bus instance.
type BulkMessage struct {
Entries []BulkMessageEntry `json:"entries"`
Topic string `json:"topic"`
Metadata map[string]string `json:"metadata"`
}
// BulkMessageEntry represents a single message inside a bulk request.
type BulkMessageEntry struct {
EntryId string `json:"entryId"` //nolint:stylecheck
Event []byte `json:"event"`
ContentType string `json:"contentType,omitempty"`
Metadata map[string]string `json:"metadata"`
}
// BulkSubscribeConfig represents the configuration for bulk subscribe.
// It depends on specific componets to support these.
type BulkSubscribeConfig struct {
MaxBulkSubCount int `json:"maxBulkSubCount"`
MaxBulkSubAwaitDurationMs int `json:"maxBulkSubAwaitDurationMs"`
MaxBulkSizeBytes int `json:"maxBulkSizeBytes"`
}

View File

@ -16,6 +16,9 @@ package pubsub
// AppResponseStatus represents a status of a PubSub response.
type AppResponseStatus string
// BulkPublishStatus represents a status of a Bulk Publish response.
type BulkPublishStatus string
const (
// Success means the message is received and processed correctly.
Success AppResponseStatus = "SUCCESS"
@ -23,9 +26,68 @@ const (
Retry AppResponseStatus = "RETRY"
// Drop means the message is received but should not be processed.
Drop AppResponseStatus = "DROP"
// PublishSucceeded represents that message was published successfully.
PublishSucceeded BulkPublishStatus = "SUCCESS"
// PublishFailed represents that message publishing failed.
PublishFailed BulkPublishStatus = "FAILED"
)
// AppResponse is the object describing the response from user code after a pubsub event.
type AppResponse struct {
Status AppResponseStatus `json:"status"`
}
// AppBulkResponseEntry Represents single response, as part of AppBulkResponse, to be
// sent by subscibed App for the corresponding single message during bulk subscribe
type AppBulkResponseEntry struct {
EntryId string `json:"entryId"` //nolint:stylecheck
Status AppResponseStatus `json:"status"`
}
// AppBulkResponse is the whole bulk subscribe response sent by App
type AppBulkResponse struct {
AppResponses []AppBulkResponseEntry `json:"statuses"`
}
// BulkPublishResponseEntry Represents single publish response, as part of BulkPublishResponse
// to be sent to publishing App for the corresponding single message during bulk publish
type BulkPublishResponseEntry struct {
EntryId string `json:"entryId"` //nolint:stylecheck
Status BulkPublishStatus `json:"status"`
Error error `json:"error"`
}
// BulkPublishResponse is the whole bulk publish response sent to App
type BulkPublishResponse struct {
Statuses []BulkPublishResponseEntry `json:"statuses"`
}
// BulkSubscribeResponseEntry Represents single subscribe response item, as part of BulkSubscribeResponse
// to be sent to building block for the corresponding single message during bulk subscribe
type BulkSubscribeResponseEntry struct {
EntryId string `json:"entryId"` //nolint:stylecheck
Error error `json:"error"`
}
// BulkSubscribeResponse is the whole bulk subscribe response sent to building block
type BulkSubscribeResponse struct {
Error error `json:"error"`
Statuses []BulkSubscribeResponseEntry `json:"statuses"`
}
// NewBulkPublishResponse returns a BulkPublishResponse with each entry having same status and error.
// This method is a helper method to map a single error/success response on BulkPublish to multiple events.
func NewBulkPublishResponse(messages []BulkMessageEntry, status BulkPublishStatus, err error) BulkPublishResponse {
response := BulkPublishResponse{}
response.Statuses = make([]BulkPublishResponseEntry, len(messages))
for i, msg := range messages {
st := BulkPublishResponseEntry{}
st.EntryId = msg.EntryId
st.Status = status
if err != nil {
st.Error = err
}
response.Statuses[i] = st
}
return response
}

79
pubsub/responses_test.go Normal file
View File

@ -0,0 +1,79 @@
/*
Copyright 2022 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package pubsub
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestNewBulkPublishResponse(t *testing.T) {
messages := []BulkMessageEntry{
{
EntryId: "1",
Event: []byte("event 1"),
Metadata: map[string]string{
"ttlInSeconds": "22",
},
ContentType: "text/plain",
},
{
EntryId: "2",
Event: []byte("event 2"),
Metadata: map[string]string{
"ttlInSeconds": "11",
},
ContentType: "text/plain",
},
}
t.Run("populate success", func(t *testing.T) {
res := NewBulkPublishResponse(messages, PublishSucceeded, nil)
assert.NotEmpty(t, res, "expected res to be populated")
assert.Equal(t, 2, len(res.Statuses), "expected two statuses")
expectedRes := BulkPublishResponse{
Statuses: []BulkPublishResponseEntry{
{
EntryId: "1",
Status: PublishSucceeded,
},
{
EntryId: "2",
Status: PublishSucceeded,
},
},
}
assert.ElementsMatch(t, expectedRes.Statuses, res.Statuses, "expected output to match")
})
t.Run("populate failure", func(t *testing.T) {
res := NewBulkPublishResponse(messages, PublishFailed, assert.AnError)
assert.NotEmpty(t, res, "expected res to be populated")
assert.Equal(t, 2, len(res.Statuses), "expected two statuses")
expectedRes := BulkPublishResponse{
Statuses: []BulkPublishResponseEntry{
{
EntryId: "1",
Status: PublishFailed,
Error: assert.AnError,
},
{
EntryId: "2",
Status: PublishFailed,
Error: assert.AnError,
},
},
}
assert.ElementsMatch(t, expectedRes.Statuses, res.Statuses, "expected output to match")
})
}

View File

@ -30,7 +30,7 @@ import (
"github.com/dapr/kit/logger"
// Blank import for the underlying PostgreSQL driver.
_ "github.com/jackc/pgx/v4/stdlib"
_ "github.com/jackc/pgx/v5/stdlib"
)
const (

View File

@ -30,7 +30,7 @@ import (
"github.com/dapr/kit/logger"
// Blank import for the underlying PostgreSQL driver.
_ "github.com/jackc/pgx/v4/stdlib"
_ "github.com/jackc/pgx/v5/stdlib"
)
const (

View File

@ -137,7 +137,7 @@ require (
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.1.11 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

View File

@ -514,8 +514,8 @@ github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjG
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
@ -1203,7 +1203,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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=
@ -1323,8 +1323,8 @@ golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/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-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -8,7 +8,7 @@ require (
github.com/dapr/dapr v1.9.0-rc.3
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20220930182601-272e358ba6a7
github.com/nacos-group/nacos-sdk-go/v2 v2.0.1
github.com/nacos-group/nacos-sdk-go/v2 v2.1.0
github.com/stretchr/testify v1.8.0
)
@ -17,7 +17,7 @@ require (
github.com/AdhityaRamadhanus/fasthttpcors v0.0.0-20170121111917-d4c07198763a // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.61.18 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704 // indirect
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e // indirect
github.com/armon/go-metrics v0.4.1 // indirect
@ -32,7 +32,6 @@ require (
github.com/fatih/color v1.13.0 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-errors/errors v1.4.0 // indirect
github.com/go-kit/log v0.2.0 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/go-logr/logr v1.2.3 // indirect
@ -104,11 +103,11 @@ require (
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/net v0.0.0-20220927171203-f486391704dc // indirect
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a // indirect
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 // indirect
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.1.11 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

View File

@ -69,8 +69,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
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/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.18 h1:zOVTBdCKFd9JbCKz9/nt+FovbjPFmb7mUnp8nH9fQBA=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.18/go.mod h1:v8ESoHo4SyHmuB4b1tJqDHxfTGEciD+yhvOU/5s1Rfk=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704 h1:PpfENOj/vPfhhy9N2OFRjpue0hjM5XqAp2thFmkXXIk=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
@ -187,9 +187,6 @@ github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSy
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-errors/errors v1.4.0 h1:2OA7MFw38+e9na72T1xgkomPb6GzZzzxvJ5U630FoRM=
github.com/go-errors/errors v1.4.0/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
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=
@ -365,8 +362,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -504,8 +501,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/nacos-group/nacos-sdk-go/v2 v2.0.1 h1:jEZjqdCDSt6ZFtl628UUwON21GxwJ+lEN/PDamQOzgU=
github.com/nacos-group/nacos-sdk-go/v2 v2.0.1/go.mod h1:SlhyCAv961LcZ198XpKfPEQqlJWt2HkL1fDLas0uy/w=
github.com/nacos-group/nacos-sdk-go/v2 v2.1.0 h1:PxRwOzHhnK6eGGvioEGkn8s6XRXmUVuXu91i2yQcdDs=
github.com/nacos-group/nacos-sdk-go/v2 v2.1.0/go.mod h1:ys/1adWeKXXzbNWfRNbaFlX/t6HVLWdpsNDvmoWTw0g=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
@ -602,7 +599,6 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
@ -707,7 +703,6 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe
go.opentelemetry.io/proto/otlp v0.16.0 h1:WHzDWdXUvbc5bG2ObdrGfaNpQz7ft7QN9HHmJlbiB1E=
go.opentelemetry.io/proto/otlp v0.16.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
@ -716,13 +711,10 @@ go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
@ -864,8 +856,9 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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=
@ -967,8 +960,9 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -989,8 +983,6 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/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-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@ -1173,7 +1165,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=

View File

@ -124,7 +124,7 @@ require (
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.1.11 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

View File

@ -412,8 +412,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -909,7 +909,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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=
@ -1012,8 +1012,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -126,7 +126,7 @@ require (
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.1.11 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

View File

@ -416,8 +416,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -914,7 +914,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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=
@ -1017,8 +1017,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -133,7 +133,7 @@ require (
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.1.11 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

View File

@ -432,8 +432,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -936,7 +936,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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=
@ -1039,8 +1039,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -130,7 +130,7 @@ require (
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.1.11 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

View File

@ -418,8 +418,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -921,7 +921,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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=
@ -1024,8 +1024,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -126,7 +126,7 @@ require (
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.1.11 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

View File

@ -411,8 +411,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -911,7 +911,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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=
@ -1014,8 +1014,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -3,7 +3,7 @@ module github.com/dapr/components-contrib/tests/certification/bindings/kafka
go 1.19
require (
github.com/Shopify/sarama v1.30.0
github.com/Shopify/sarama v1.37.2
github.com/cenkalti/backoff/v4 v4.1.3
github.com/dapr/components-contrib v1.9.0-rc.1
github.com/dapr/components-contrib/tests/certification v0.0.0-20220519061249-c2cb1dad5bb0
@ -27,7 +27,7 @@ require (
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/eapache/go-resiliency v1.2.0 // indirect
github.com/eapache/go-resiliency v1.3.0 // indirect
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect
github.com/eapache/queue v1.1.0 // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
@ -59,19 +59,18 @@ require (
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/hashicorp/go-uuid v1.0.2 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/hashicorp/serf v0.9.6 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
github.com/jcmturner/gofork v1.0.0 // indirect
github.com/jcmturner/gokrb5/v8 v8.4.2 // indirect
github.com/jcmturner/gofork v1.7.6 // indirect
github.com/jcmturner/gokrb5/v8 v8.4.3 // indirect
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/jhump/protoreflect v1.13.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.15.11 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
@ -82,7 +81,7 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/openzipkin/zipkin-go v0.4.0 // indirect
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
github.com/pierrec/lz4/v4 v4.1.17 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.12.2 // indirect
@ -91,6 +90,7 @@ require (
github.com/prometheus/procfs v0.7.3 // indirect
github.com/prometheus/statsd_exporter v0.22.3 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rogpeppe/go-internal v1.6.1 // indirect
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/sony/gobreaker v0.4.2-0.20210216022020-dd874f9dd33b // indirect
@ -101,8 +101,8 @@ require (
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.40.0 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.0.2 // indirect
github.com/xdg-go/stringprep v1.0.2 // indirect
github.com/xdg-go/scram v1.1.1 // indirect
github.com/xdg-go/stringprep v1.0.3 // indirect
go.opencensus.io v0.23.0 // indirect
go.opentelemetry.io/otel v1.7.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 // indirect
@ -121,7 +121,7 @@ require (
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.1.11 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

View File

@ -60,10 +60,11 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/Shopify/sarama v1.30.0 h1:TOZL6r37xJBDEMLx4yjB77jxbZYXPaDow08TSK6vIL0=
github.com/Shopify/sarama v1.30.0/go.mod h1:zujlQQx1kzHsh4jfV1USnptCQrHAEZ2Hk8fTKCulPVs=
github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae h1:ePgznFqEG1v3AjMklnK8H7BSc++FDSo7xfK9K7Af+0Y=
github.com/Shopify/sarama v1.37.2 h1:LoBbU0yJPte0cE5TZCGdlzZRmMgMtZU/XgnUKZg9Cv4=
github.com/Shopify/sarama v1.37.2/go.mod h1:Nxye/E+YPru//Bpaorfhc3JsSGYwCaDDj+R4bK52U5o=
github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae/go.mod h1:/cvHQkZ1fst0EmZnA5dFtiQdWCNCFYzb+uE2vqVgvx0=
github.com/Shopify/toxiproxy/v2 v2.5.0 h1:i4LPT+qrSlKNtQf5QliVjdP08GyAH8+BUIc9gT0eahc=
github.com/agrea/ptr v0.0.0-20180711073057-77a518d99b7b h1:WMhlIaJkDgEQSVJQM06YV+cYUl1r5OY5//ijMXJNqtA=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@ -145,8 +146,9 @@ 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/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q=
github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-resiliency v1.3.0 h1:RRL0nge+cWGlxXbUzJ7yMcq6w2XBEr19dCN6HECGaT0=
github.com/eapache/go-resiliency v1.3.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
@ -179,7 +181,6 @@ github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoD
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.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
@ -364,8 +365,9 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -395,12 +397,14 @@ github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFK
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8=
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg=
github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo=
github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
github.com/jcmturner/gokrb5/v8 v8.4.2 h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJzodkA=
github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc=
github.com/jcmturner/gokrb5/v8 v8.4.3 h1:iTonLeSJOn7MVUtyMT+arAn5AKAPrkilzhGw8wE/Tq8=
github.com/jcmturner/gokrb5/v8 v8.4.3/go.mod h1:dqRwJGXznQrzw6cWmyo6kH+E7jksEQG/CyVWsJEsJO0=
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
@ -441,7 +445,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@ -531,8 +534,9 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -654,10 +658,12 @@ github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxn
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc=
github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@ -741,6 +747,7 @@ golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be h1:fmw3UbQh+nxngCAHrDCCztao/kbYFnWjoqop8dHx05A=
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -835,6 +842,7 @@ golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220725212005-46097bf591d3/go.mod h1:AaygXjzTFtRAg2ttMY5RMuhpJ3cNnI0XpyFJD1iQRSM=
golang.org/x/net v0.0.0-20220927171203-f486391704dc h1:FxpXZdoBqT8RjqTy6i1E8nXHhW21wK7ptQ/EPIGxzPQ=
golang.org/x/net v0.0.0-20220927171203-f486391704dc/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -866,7 +874,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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=
@ -946,6 +954,7 @@ golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -968,8 +977,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -101,7 +101,7 @@ require (
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.1.11 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

View File

@ -357,8 +357,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -840,7 +840,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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=
@ -942,8 +942,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -56,15 +56,10 @@ require (
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/hashicorp/serf v0.9.6 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.13.0 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/pgtype v1.12.0 // indirect
github.com/jackc/pgx/v4 v4.17.0 // indirect
github.com/jackc/puddle v1.2.1 // indirect
github.com/jackc/pgx/v5 v5.0.2 // indirect
github.com/jackc/puddle/v2 v2.0.0 // indirect
github.com/jhump/protoreflect v1.13.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.15.11 // indirect
@ -85,6 +80,7 @@ require (
github.com/prometheus/common v0.35.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/prometheus/statsd_exporter v0.22.3 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/sony/gobreaker v0.4.2-0.20210216022020-dd874f9dd33b // indirect
@ -112,7 +108,7 @@ require (
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.1.11 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

View File

@ -53,7 +53,6 @@ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBp
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
@ -117,8 +116,6 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
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/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
@ -127,12 +124,10 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/dapr/dapr v1.9.0-rc.3 h1:WLATw9Ky44lM5CVbzrd/M04yQXON4+NL9GH6K89v8Mo=
@ -218,8 +213,6 @@ github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
@ -362,8 +355,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -389,54 +382,14 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys=
github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y=
github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w=
github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
github.com/jackc/pgx/v4 v4.17.0 h1:Hsx+baY8/zU2WtPLQyZi8WbecgcsWEeyoK1jvg/WgIo=
github.com/jackc/pgx/v4 v4.17.0/go.mod h1:Gd6RmOhtFLTu8cp/Fhq4kP195KrshxYJH3oW8AWJ1pw=
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.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.2.1 h1:gI8os0wpRXFd4FiAY2dWiqRK037tjj3t7rKFeO4X5iw=
github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/pgx/v5 v5.0.2 h1:V+EonE9i33VwJR9YIHRdglAmrODLLkwIdHjko6b1rRk=
github.com/jackc/pgx/v5 v5.0.2/go.mod h1:JBbvW3Hdw77jKl9uJrEDATUZIFM2VFPzRq4RWIhkF4o=
github.com/jackc/puddle/v2 v2.0.0 h1:Kwk/AlLigcnZsDssc3Zun1dk1tAtQNPaBBxBHWn0Mjc=
github.com/jackc/puddle/v2 v2.0.0/go.mod h1:itE7ZJY8xnoo0JqJEpSMprN0f+NQkMCuEV/N9j8h0oc=
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
@ -474,22 +427,17 @@ github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e
github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c=
github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
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/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
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/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@ -498,7 +446,6 @@ 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.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
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.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@ -506,8 +453,6 @@ github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
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.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
@ -634,22 +579,16 @@ github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqn
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d h1:Q+gqLBOPkFGHyCJxXMRqtUgUbTjI8/Ze8vu8GGyNFwo=
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
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=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
@ -681,7 +620,6 @@ github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ai
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@ -716,7 +654,6 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
@ -764,10 +701,7 @@ go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.opentelemetry.io/proto/otlp v0.16.0 h1:WHzDWdXUvbc5bG2ObdrGfaNpQz7ft7QN9HHmJlbiB1E=
go.opentelemetry.io/proto/otlp v0.16.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
@ -775,21 +709,15 @@ go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -798,13 +726,9 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be h1:fmw3UbQh+nxngCAHrDCCztao/kbYFnWjoqop8dHx05A=
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -863,7 +787,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
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-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-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -931,7 +854,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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=
@ -942,7 +865,6 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -950,7 +872,6 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1016,7 +937,6 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
@ -1036,8 +956,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -1048,7 +968,6 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
@ -1056,12 +975,9 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
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-20190907020128-2ca718005c18/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-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@ -1071,7 +987,6 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn
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-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
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=
@ -1107,8 +1022,6 @@ golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyj
golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM=
golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY=
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
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/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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -1245,7 +1158,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=

View File

@ -8,7 +8,7 @@ require (
github.com/dapr/dapr v1.9.0-rc.3
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20220930182601-272e358ba6a7
github.com/rabbitmq/amqp091-go v1.3.4
github.com/rabbitmq/amqp091-go v1.5.0
github.com/stretchr/testify v1.8.0
go.uber.org/multierr v1.8.0
)
@ -104,7 +104,7 @@ require (
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.1.11 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

View File

@ -356,8 +356,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -566,8 +566,8 @@ github.com/prometheus/statsd_exporter v0.22.3 h1:4gxpAtnt/py8g0kUHad9f3DbU7flDeL
github.com/prometheus/statsd_exporter v0.22.3/go.mod h1:N4Z1+iSqc9rnxlT1N8Qn3l65Vzb5t4Uq0jpg8nxyhio=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rabbitmq/amqp091-go v1.1.0/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0VTJ0kHRghqbM=
github.com/rabbitmq/amqp091-go v1.3.4 h1:tXuIslN1nhDqs2t6Jrz3BAoqvt4qIZzxvdbdcxWtHYU=
github.com/rabbitmq/amqp091-go v1.3.4/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0VTJ0kHRghqbM=
github.com/rabbitmq/amqp091-go v1.5.0 h1:VouyHPBu1CrKyJVfteGknGOGCzmOz0zcv/tONLkb7rg=
github.com/rabbitmq/amqp091-go v1.5.0/go.mod h1:JsV0ofX5f1nwOGafb8L5rBItt9GyhfQfcJj+oyz0dGg=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
@ -844,7 +844,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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=
@ -946,8 +946,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -103,7 +103,7 @@ require (
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.1.11 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

View File

@ -361,8 +361,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -847,7 +847,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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=
@ -949,8 +949,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -109,7 +109,7 @@ require (
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220622171453-ea41d75dfa0f // indirect
google.golang.org/grpc v1.48.0 // indirect

View File

@ -356,8 +356,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -841,7 +841,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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=
@ -943,8 +943,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -132,7 +132,7 @@ require (
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.1.11 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

View File

@ -432,8 +432,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -934,7 +934,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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=
@ -1037,8 +1037,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -130,7 +130,7 @@ require (
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.1.11 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

View File

@ -418,8 +418,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -921,7 +921,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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=
@ -1024,8 +1024,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -3,7 +3,7 @@ module github.com/dapr/components-contrib/tests/certification/pubsub/kafka
go 1.19
require (
github.com/Shopify/sarama v1.30.0
github.com/Shopify/sarama v1.37.2
github.com/cenkalti/backoff/v4 v4.1.3
github.com/dapr/components-contrib v1.9.0-rc.1
github.com/dapr/components-contrib/tests/certification v0.0.0-20220519061249-c2cb1dad5bb0
@ -27,7 +27,7 @@ require (
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/eapache/go-resiliency v1.2.0 // indirect
github.com/eapache/go-resiliency v1.3.0 // indirect
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect
github.com/eapache/queue v1.1.0 // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
@ -59,19 +59,18 @@ require (
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/hashicorp/go-uuid v1.0.2 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/hashicorp/serf v0.9.6 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
github.com/jcmturner/gofork v1.0.0 // indirect
github.com/jcmturner/gokrb5/v8 v8.4.2 // indirect
github.com/jcmturner/gofork v1.7.6 // indirect
github.com/jcmturner/gokrb5/v8 v8.4.3 // indirect
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/jhump/protoreflect v1.13.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.15.11 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
@ -82,7 +81,7 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/openzipkin/zipkin-go v0.4.0 // indirect
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
github.com/pierrec/lz4/v4 v4.1.17 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.12.2 // indirect
@ -91,6 +90,7 @@ require (
github.com/prometheus/procfs v0.7.3 // indirect
github.com/prometheus/statsd_exporter v0.22.3 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rogpeppe/go-internal v1.6.1 // indirect
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/sony/gobreaker v0.4.2-0.20210216022020-dd874f9dd33b // indirect
@ -101,8 +101,8 @@ require (
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.40.0 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.0.2 // indirect
github.com/xdg-go/stringprep v1.0.2 // indirect
github.com/xdg-go/scram v1.1.1 // indirect
github.com/xdg-go/stringprep v1.0.3 // indirect
go.opencensus.io v0.23.0 // indirect
go.opentelemetry.io/otel v1.7.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 // indirect
@ -121,7 +121,7 @@ require (
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.1.11 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

View File

@ -60,10 +60,11 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/Shopify/sarama v1.30.0 h1:TOZL6r37xJBDEMLx4yjB77jxbZYXPaDow08TSK6vIL0=
github.com/Shopify/sarama v1.30.0/go.mod h1:zujlQQx1kzHsh4jfV1USnptCQrHAEZ2Hk8fTKCulPVs=
github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae h1:ePgznFqEG1v3AjMklnK8H7BSc++FDSo7xfK9K7Af+0Y=
github.com/Shopify/sarama v1.37.2 h1:LoBbU0yJPte0cE5TZCGdlzZRmMgMtZU/XgnUKZg9Cv4=
github.com/Shopify/sarama v1.37.2/go.mod h1:Nxye/E+YPru//Bpaorfhc3JsSGYwCaDDj+R4bK52U5o=
github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae/go.mod h1:/cvHQkZ1fst0EmZnA5dFtiQdWCNCFYzb+uE2vqVgvx0=
github.com/Shopify/toxiproxy/v2 v2.5.0 h1:i4LPT+qrSlKNtQf5QliVjdP08GyAH8+BUIc9gT0eahc=
github.com/agrea/ptr v0.0.0-20180711073057-77a518d99b7b h1:WMhlIaJkDgEQSVJQM06YV+cYUl1r5OY5//ijMXJNqtA=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@ -145,8 +146,9 @@ 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/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q=
github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-resiliency v1.3.0 h1:RRL0nge+cWGlxXbUzJ7yMcq6w2XBEr19dCN6HECGaT0=
github.com/eapache/go-resiliency v1.3.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
@ -179,7 +181,6 @@ github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoD
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.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
@ -364,8 +365,9 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -395,12 +397,14 @@ github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFK
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8=
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg=
github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo=
github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
github.com/jcmturner/gokrb5/v8 v8.4.2 h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJzodkA=
github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc=
github.com/jcmturner/gokrb5/v8 v8.4.3 h1:iTonLeSJOn7MVUtyMT+arAn5AKAPrkilzhGw8wE/Tq8=
github.com/jcmturner/gokrb5/v8 v8.4.3/go.mod h1:dqRwJGXznQrzw6cWmyo6kH+E7jksEQG/CyVWsJEsJO0=
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
@ -441,7 +445,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@ -531,8 +534,9 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -654,10 +658,12 @@ github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxn
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc=
github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@ -741,6 +747,7 @@ golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be h1:fmw3UbQh+nxngCAHrDCCztao/kbYFnWjoqop8dHx05A=
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -835,6 +842,7 @@ golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220725212005-46097bf591d3/go.mod h1:AaygXjzTFtRAg2ttMY5RMuhpJ3cNnI0XpyFJD1iQRSM=
golang.org/x/net v0.0.0-20220927171203-f486391704dc h1:FxpXZdoBqT8RjqTy6i1E8nXHhW21wK7ptQ/EPIGxzPQ=
golang.org/x/net v0.0.0-20220927171203-f486391704dc/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -866,7 +874,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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=
@ -946,6 +954,7 @@ golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -968,8 +977,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -9,7 +9,7 @@ require (
github.com/dapr/dapr v1.9.0-rc.3
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20220930182601-272e358ba6a7
github.com/eclipse/paho.mqtt.golang v1.3.5
github.com/eclipse/paho.mqtt.golang v1.4.1
github.com/stretchr/testify v1.8.0
go.uber.org/multierr v1.8.0
)
@ -104,11 +104,11 @@ require (
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/net v0.0.0-20220927171203-f486391704dc // indirect
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a // indirect
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 // indirect
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.1.11 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

View File

@ -360,8 +360,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -851,8 +851,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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=
@ -954,8 +954,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -9,7 +9,7 @@ require (
github.com/dapr/dapr v1.9.0-rc.3
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20220930182601-272e358ba6a7
github.com/rabbitmq/amqp091-go v1.3.4
github.com/rabbitmq/amqp091-go v1.5.0
github.com/stretchr/testify v1.8.0
go.uber.org/multierr v1.8.0
)
@ -104,7 +104,7 @@ require (
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.1.11 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

View File

@ -356,8 +356,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -566,8 +566,8 @@ github.com/prometheus/statsd_exporter v0.22.3 h1:4gxpAtnt/py8g0kUHad9f3DbU7flDeL
github.com/prometheus/statsd_exporter v0.22.3/go.mod h1:N4Z1+iSqc9rnxlT1N8Qn3l65Vzb5t4Uq0jpg8nxyhio=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rabbitmq/amqp091-go v1.1.0/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0VTJ0kHRghqbM=
github.com/rabbitmq/amqp091-go v1.3.4 h1:tXuIslN1nhDqs2t6Jrz3BAoqvt4qIZzxvdbdcxWtHYU=
github.com/rabbitmq/amqp091-go v1.3.4/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0VTJ0kHRghqbM=
github.com/rabbitmq/amqp091-go v1.5.0 h1:VouyHPBu1CrKyJVfteGknGOGCzmOz0zcv/tONLkb7rg=
github.com/rabbitmq/amqp091-go v1.5.0/go.mod h1:JsV0ofX5f1nwOGafb8L5rBItt9GyhfQfcJj+oyz0dGg=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
@ -844,7 +844,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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=
@ -946,8 +946,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

Some files were not shown because too many files have changed in this diff Show More