Merge branch 'master' into merge-1.9
Signed-off-by: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>
This commit is contained in:
commit
3bc20a1de5
|
@ -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 }}%'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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() {
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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
236
go.mod
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}()
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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"`
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
}
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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"))
|
||||
}
|
||||
|
|
|
@ -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, ®oResult); 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
|
||||
}
|
||||
|
|
|
@ -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]))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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()
|
||||
})
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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"`
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
})
|
||||
}
|
|
@ -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 (
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue