From ee6a0036933f9870ed530c649134f8d2f76c2e20 Mon Sep 17 00:00:00 2001 From: Lyubo Kamenov Date: Tue, 10 Sep 2024 16:46:05 -0400 Subject: [PATCH] New pubsub eventbus impl (#131) * New pubsub eventbus impl --------- Co-authored-by: Samir Ketema --- .github/workflows/build.yml | 2 +- .gitignore | 2 + .golangci.goheader.template | 2 +- .golangci.yml | 11 +- .mockery.yaml | 24 + Makefile | 16 +- README.md | 51 +- cmd/connector/acceptance_test.go | 2 +- cmd/connector/main.go | 6 +- cmd/connector/oauth_client_mock_test.go | 5 +- cmd/connector/streaming_client_mock_test.go | 2 +- go.mod | 65 +- go.sum | 94 +- internal/cometd/client.go | 2 +- internal/cometd/requests/connect.go | 2 +- internal/cometd/requests/handshake.go | 3 +- internal/cometd/responses/subscribe_test.go | 6 +- internal/cometd/responses/unsubscribe_test.go | 6 +- .../responses/unsuccessful_handshake_test.go | 2 +- internal/operation.go | 2 +- internal/salesforce/oauth/client.go | 4 +- .../salesforce/oauth/http_client_moq_test.go | 23 +- internal/salesforce/oauth/response/failure.go | 2 +- .../salesforce/oauth/response/failure_test.go | 2 +- internal/utils/http_response_decoder_test.go | 8 +- proto/buf.gen.yaml | 14 + proto/buf.lock | 2 + proto/buf.yaml | 7 + proto/eventbus/v1/pubsub_api.pb.go | 1864 +++++++++++++++++ proto/eventbus/v1/pubsub_api.proto | 413 ++++ proto/eventbus/v1/pubsub_api_grpc.pb.go | 544 +++++ source/source.go | 10 +- source_pubsub/client.go | 706 +++++++ source_pubsub/client_test.go | 74 + source_pubsub/config.go | 119 ++ source_pubsub/mock_authenticator_test.go | 147 ++ source_pubsub/mock_client_test.go | 264 +++ source_pubsub/mock_pub_sub_client_test.go | 480 +++++ .../mock_pub_sub_subscribe_client_test.go | 430 ++++ source_pubsub/oauth.go | 167 ++ source_pubsub/paramgen_config.go | 101 + source_pubsub/position/position.go | 90 + source_pubsub/source.go | 176 ++ source_pubsub/source_test.go | 124 ++ tools.go | 3 + 45 files changed, 5954 insertions(+), 125 deletions(-) create mode 100644 .mockery.yaml create mode 100644 proto/buf.gen.yaml create mode 100644 proto/buf.lock create mode 100644 proto/buf.yaml create mode 100644 proto/eventbus/v1/pubsub_api.pb.go create mode 100644 proto/eventbus/v1/pubsub_api.proto create mode 100644 proto/eventbus/v1/pubsub_api_grpc.pb.go create mode 100644 source_pubsub/client.go create mode 100644 source_pubsub/client_test.go create mode 100644 source_pubsub/config.go create mode 100644 source_pubsub/mock_authenticator_test.go create mode 100644 source_pubsub/mock_client_test.go create mode 100644 source_pubsub/mock_pub_sub_client_test.go create mode 100644 source_pubsub/mock_pub_sub_subscribe_client_test.go create mode 100644 source_pubsub/oauth.go create mode 100644 source_pubsub/paramgen_config.go create mode 100644 source_pubsub/position/position.go create mode 100644 source_pubsub/source.go create mode 100644 source_pubsub/source_test.go diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2445e13..cb1013c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,4 +17,4 @@ jobs: go-version-file: 'go.mod' - name: Test - run: make test GOTEST_FLAGS="-v -count=1" + run: make test diff --git a/.gitignore b/.gitignore index ac8eabe..d85f5d6 100644 --- a/.gitignore +++ b/.gitignore @@ -132,3 +132,5 @@ $RECYCLE.BIN/ ### Project ### # Binary built with `make build` /conduit-connector-salesforce + +.env diff --git a/.golangci.goheader.template b/.golangci.goheader.template index 90190df..c29f25a 100644 --- a/.golangci.goheader.template +++ b/.golangci.goheader.template @@ -1,4 +1,4 @@ -Copyright © {{ copyright-year }} Meroxa, Inc. and Miquido +Copyright © {{ copyright-year }} Meroxa, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/.golangci.yml b/.golangci.yml index 18a877f..3b5a9a2 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -11,11 +11,12 @@ linters-settings: min-complexity: 20 goconst: ignore-tests: true - goheader: - template-path: '.golangci.goheader.template' - values: - regexp: - copyright-year: 20[2-9]\d + # TODO: Skip this until ready to merge. + # goheader: + # template-path: '.golangci.goheader.template' + # values: + # regexp: + # copyright-year: 20[2-9]\d linters: # please, do not use `enable-all`: it's deprecated and will be removed soon. diff --git a/.mockery.yaml b/.mockery.yaml new file mode 100644 index 0000000..b3abfe5 --- /dev/null +++ b/.mockery.yaml @@ -0,0 +1,24 @@ +--- +with-expecter: true +inpackage: true +disable-version-string: true +filename: "mock_{{.InterfaceName | snakecase}}_test.go" +mockname: "mock{{.InterfaceName | firstUpper}}" +dir: "{{.InterfaceDir}}" +packages: + github.com/conduitio-labs/conduit-connector-salesforce/proto/eventbus/v1: + interfaces: + PubSubClient: + config: + dir: source_pubsub + inpackage: false + outpkg: source + PubSub_SubscribeClient: + config: + dir: source_pubsub + inpackage: false + outpkg: source + github.com/conduitio-labs/conduit-connector-salesforce/source: + interfaces: + authenticator: null + client: null diff --git a/Makefile b/Makefile index 7543be4..a1b6512 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: build test lint +.PHONY: build test lint fmt proto VERSION=$(shell git describe --tags --dirty --always) @@ -8,8 +8,20 @@ build: test: go test $(GOTEST_FLAGS) -race ./... +fmt: + gofumpt -l -w . + gci write --skip-generated . + lint: - golangci-lint run + golangci-lint run -v + +proto: + cd proto && buf generate + +generate: + go generate ./... + mockery + .PHONY: install-tools install-tools: diff --git a/README.md b/README.md index d578d46..a7ea290 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Run `make`. ## Source -The Source connector subscribes to given list of topics and listens for events published by Salesforce. +The Source connector subscribes to Salesforce platform events and queries published events in real time. ### How it works @@ -60,6 +60,8 @@ There may be need to reconnect while connector is working. Server returns condit ### Configuration Options +## Destination + | name | description | required | default | |-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------| | `environment` | Authorization service based on Organization’s Domain Name (e.g.: https://MyDomainName.my.salesforce.com -> `MyDomainName`) or `sandbox` for test environment. | `true` | | @@ -71,9 +73,28 @@ There may be need to reconnect while connector is working. Server returns condit | `pushTopicsNames` | The comma-separated list of names of the Push Topics to listen to. All values will be prefixed with `/topic/`. All values will have white spaces trimmed. Any empty value is skipped. All Topics have to exist for connector to start working. | `true` | | | `keyField` | The name of the Response's field that should be used as a Payload's Key. Empty value will set it to `nil`. | `false` | `"Id"` | +## Source + + +| name | description | required | default | +|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------| +| `oauthEndpoint` | Authorization service based on Organization’s Domain Name (e.g.: https://MyDomainName.my.salesforce.com ) | | `true` | +| `clientId` | OAuth Client ID (Consumer Key) | `true` | | +| `clientSecret` | OAuth Client Secret (Consumer Secret) | `true` | | +| `username` | Username. | `false` | | +| ~~`topicName`~~ | Event topic name for your event (e.g: /event/Accepted_Quote__e) **Deprecated: use `topicNames` instead** | `false` || +| `topicsNames` | One or multiple comma separated topic names the source will subscribe to (e.g */event/Test__e, /event/Test2__e*). | `true` || +| `retryCount` | Number of times the connector will retry is the connection to a topic breaks. | `false` | `10` | +| `replayPreset` | The position from which connector will start reading events, either 'latest' or 'earliest'. Latest will pull only newly created events, and earlies will pull any events that are currently in the topic. | `false` | `earliest` | +| `pollingPeriod` | The client event polling interval between each data read on the topic. | `false` | `100ms` | +| `insecureSkipVerify` | Disables certificate validation. | `false` | `false` | + + ### Step-by-step configuration example -There are a couple of steps that need to be done to start working with Salesforce connector. +## Destination + +There are a couple of steps that need to be done to start working with Salesforce connector as destination. 1. Log in into Your Salesforce account, e.g. https://my-demo-app.my.salesforce.com. The environment is `my-demo-app`. 2. First, if not already done, You need to create connected app and enable OAuth: [Enable OAuth Settings for API Integration](https://help.salesforce.com/s/articleView?id=sf.connected_app_create_api_integration.htm&type=5). @@ -105,6 +126,32 @@ There are a couple of steps that need to be done to start working with Salesforc Later, this may be utilized by other connectors, e.g. [Elasticsearch connector](https://github.com/conduitio-labs/conduit-connector-elasticsearch) will create Document with ID of Record's Key when available. +## Source + +1. Log in into Your Salesforce account, e.g. https://my-demo-app.my.salesforce.com. The environment is `my-demo-app`. +2. First, if not already done, You need to create connected app and enable OAuth: [Enable OAuth Settings for API Integration](https://help.salesforce.com/s/articleView?id=sf.connected_app_create_api_integration.htm&type=5). + + The callback URL is required, but not relevant for this connector, so you can put anything there. + + Successfully configured app example can be seen below: + + ![Connected App example](docs/connect_and_configure_app.png) +3. Copy **Consumer Key** and **Consumer Secret**. If You need these values once again You can always find them in _Setup -> Apps -> App Manager_, find app on the list and choose _View_ option. + ![View OAuth tokens](docs/view_oauth_tokens.png) + +4. You will need to set following settings on the application, refer to ![OAuth Client Credentials Flow Requirements](https://help.salesforce.com/s/articleView?id=sf.connected_app_client_credentials_setup.htm&type=5) . + Make sure the user you are attaching to the application has "API ENABLED" permission set on their account. + +5. Set up event: + +6. Once done, You can begin with configuring the connector: + 1. Set `oauthEndpount`, it should be a full url to your salesforce, (e.g: https://mysalesforce.salesforce.com ) + 2. Use Step 3 **Consumer Key** value as `clientId` config. + 3. Use Step 3 **Consumer Secret** value as `clientSecret` config. + 4. Set `topicNames` to either one or multiple event topic names the connector will subscribe to, should contain event in topic name such as `/event/Test__e`. + 5. Set any optional config fields as needed. + + ## Testing Run `make test` to run all the unit and integration tests. diff --git a/cmd/connector/acceptance_test.go b/cmd/connector/acceptance_test.go index 1b9a2db..2300521 100644 --- a/cmd/connector/acceptance_test.go +++ b/cmd/connector/acceptance_test.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Meroxa, Inc. and Miquido +// Copyright © 2022 Meroxa, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/cmd/connector/main.go b/cmd/connector/main.go index cead724..d9611b7 100644 --- a/cmd/connector/main.go +++ b/cmd/connector/main.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Meroxa, Inc. and Miquido +// Copyright © 2022 Meroxa, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,14 +16,14 @@ package main import ( sf "github.com/conduitio-labs/conduit-connector-salesforce" - sfSource "github.com/conduitio-labs/conduit-connector-salesforce/source" + sfSourcePubsub "github.com/conduitio-labs/conduit-connector-salesforce/source_pubsub" sdk "github.com/conduitio/conduit-connector-sdk" ) func main() { sdk.Serve(sdk.Connector{ NewSpecification: sf.Specification, - NewSource: sfSource.NewSource, + NewSource: sfSourcePubsub.NewSource, NewDestination: nil, }) } diff --git a/cmd/connector/oauth_client_mock_test.go b/cmd/connector/oauth_client_mock_test.go index 1b503b4..a26ef3c 100644 --- a/cmd/connector/oauth_client_mock_test.go +++ b/cmd/connector/oauth_client_mock_test.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Meroxa, Inc. and Miquido +// Copyright © 2022 Meroxa, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,8 +20,7 @@ import ( "github.com/conduitio-labs/conduit-connector-salesforce/internal/salesforce/oauth/response" ) -type oAuthClientMock struct { -} +type oAuthClientMock struct{} func (c *oAuthClientMock) Authenticate(_ context.Context) (response.TokenResponse, error) { return response.TokenResponse{ diff --git a/cmd/connector/streaming_client_mock_test.go b/cmd/connector/streaming_client_mock_test.go index 28ac9cb..b925c55 100644 --- a/cmd/connector/streaming_client_mock_test.go +++ b/cmd/connector/streaming_client_mock_test.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Meroxa, Inc. and Miquido +// Copyright © 2022 Meroxa, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/go.mod b/go.mod index 508f2ce..eebc39f 100644 --- a/go.mod +++ b/go.mod @@ -9,11 +9,31 @@ require ( github.com/conduitio/conduit-connector-sdk v0.10.0 github.com/golangci/golangci-lint v1.61.0 github.com/jaswdr/faker v1.19.1 + github.com/linkedin/goavro/v2 v2.13.0 github.com/stretchr/testify v1.9.0 golang.org/x/net v0.29.0 + google.golang.org/grpc v1.66.1 + google.golang.org/protobuf v1.34.3-0.20240816073751-94ecbc261689 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 ) +require ( + dario.cat/mergo v1.0.1 // indirect + github.com/bufbuild/protocompile v0.14.1 // indirect + github.com/google/pprof v0.0.0-20240903155634-a8630aee4ab9 // indirect + github.com/hamba/avro/v2 v2.25.2 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/sagikazarmark/locafero v0.6.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/twmb/go-cache v1.2.1 // indirect + go.uber.org/mock v0.4.0 // indirect +) + require ( 4d63.com/gocheckcompilerdirectives v1.2.1 // indirect 4d63.com/gochecknoglobals v0.2.1 // indirect @@ -28,7 +48,7 @@ require ( github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.3.0 // indirect - github.com/Masterminds/sprig/v3 v3.2.3 // indirect + github.com/Masterminds/sprig/v3 v3.3.0 // indirect github.com/OpenPeeDeeP/depguard/v2 v2.2.0 // indirect github.com/alecthomas/go-check-sumtype v0.1.4 // indirect github.com/alexkohler/nakedret/v2 v2.0.4 // indirect @@ -36,6 +56,7 @@ require ( github.com/alingse/asasalint v0.0.11 // indirect github.com/ashanbrown/forbidigo v1.6.0 // indirect github.com/ashanbrown/makezero v1.1.1 // indirect + github.com/avast/retry-go/v4 v4.6.0 github.com/beorn7/perks v1.0.1 // indirect github.com/bkielbasa/cyclop v1.2.1 // indirect github.com/blizzy78/varnamelen v0.8.0 // indirect @@ -52,7 +73,7 @@ require ( github.com/ckaznocha/intrange v0.2.0 // indirect github.com/conduitio/conduit-connector-protocol v0.7.0 // indirect github.com/curioswitch/go-reassign v0.2.0 // indirect - github.com/daixiang0/gci v0.13.5 // indirect + github.com/daixiang0/gci v0.13.5 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/denis-tingaikin/go-header v0.5.0 // indirect github.com/ettle/strcase v0.2.0 // indirect @@ -76,6 +97,7 @@ require ( github.com/goccy/go-json v0.10.3 // indirect github.com/gofrs/flock v0.12.1 // indirect github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 // indirect github.com/golangci/misspell v0.6.0 // indirect @@ -90,22 +112,19 @@ require ( github.com/gostaticanalysis/comment v1.4.2 // indirect github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect github.com/gostaticanalysis/nilerr v0.1.1 // indirect - github.com/hamba/avro/v2 v2.24.0 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-plugin v1.6.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect - github.com/huandu/xstrings v1.3.3 // indirect - github.com/imdario/mergo v0.3.11 // indirect + github.com/huandu/xstrings v1.5.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jgautheron/goconst v1.7.1 // indirect github.com/jingyugao/rowserrcheck v1.1.1 // indirect github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect github.com/jjti/go-spancheck v0.6.2 // indirect github.com/jpillora/backoff v1.0.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect github.com/julz/importas v0.1.0 // indirect github.com/karamaru-alpha/copyloopvar v1.1.0 // indirect github.com/kisielk/errcheck v1.7.0 // indirect @@ -126,15 +145,13 @@ require ( github.com/matryer/is v1.4.1 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mgechev/revive v1.3.9 // indirect - github.com/mitchellh/copystructure v1.0.0 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/mitchellh/reflectwalk v1.0.0 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moricho/tparallel v0.3.2 // indirect github.com/nakabonne/nestif v0.3.1 // indirect github.com/nishanths/exhaustive v0.12.0 // indirect @@ -145,36 +162,32 @@ require ( github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/polyfloyd/go-errorlint v1.6.0 // indirect - github.com/prometheus/client_golang v1.19.1 // indirect + github.com/prometheus/client_golang v1.20.3 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.54.0 // indirect + github.com/prometheus/common v0.59.1 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 // indirect github.com/quasilyte/go-ruleguard/dsl v0.3.22 // indirect github.com/quasilyte/gogrep v0.5.0 // indirect github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect - github.com/rivo/uniseg v0.4.7 // indirect github.com/rs/zerolog v1.33.0 // indirect github.com/ryancurrah/gomodguard v1.3.5 // indirect github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect - github.com/sagikazarmark/locafero v0.6.0 // indirect - github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect github.com/sashamelentyev/interfacebloat v1.1.0 // indirect github.com/sashamelentyev/usestdlibvars v1.27.0 // indirect github.com/securego/gosec/v2 v2.21.2 // indirect github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect - github.com/shopspring/decimal v1.2.0 // indirect + github.com/shopspring/decimal v1.4.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/sivchari/containedctx v1.0.3 // indirect github.com/sivchari/tenv v1.10.0 // indirect github.com/sonatard/noctx v0.0.2 // indirect - github.com/sourcegraph/conc v0.3.0 // indirect github.com/sourcegraph/go-diff v0.7.0 // indirect github.com/spf13/afero v1.11.0 // indirect - github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/cast v1.7.0 // indirect github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.19.0 // indirect @@ -183,12 +196,11 @@ require ( github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/tdakkota/asciicheck v0.2.0 // indirect - github.com/tetafro/godot v1.4.17 // indirect + github.com/tetafro/godot v1.4.18 // indirect github.com/timakin/bodyclose v0.0.0-20240125160201-f835fa56326a // indirect github.com/timonwong/loggercheck v0.9.4 // indirect github.com/tomarrell/wrapcheck/v2 v2.9.0 // indirect github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect - github.com/twmb/go-cache v1.2.1 // indirect github.com/ultraware/funlen v0.1.0 // indirect github.com/ultraware/whitespace v0.1.1 // indirect github.com/uudashr/gocognit v1.1.3 // indirect @@ -201,25 +213,22 @@ require ( go-simpler.org/sloglint v0.7.2 // indirect go.uber.org/automaxprocs v1.5.3 // indirect go.uber.org/goleak v1.3.0 // indirect - go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.27.0 // indirect - golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // indirect - golang.org/x/exp/typeparams v0.0.0-20240613232115-7f521ea00fb8 // indirect + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect + golang.org/x/exp/typeparams v0.0.0-20240909161429-701f63a606c0 // indirect golang.org/x/mod v0.21.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.18.0 // indirect golang.org/x/time v0.6.0 // indirect - golang.org/x/tools v0.24.0 // indirect + golang.org/x/tools v0.25.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/grpc v1.66.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect honnef.co/go/tools v0.5.1 // indirect - mvdan.cc/gofumpt v0.7.0 // indirect + mvdan.cc/gofumpt v0.7.0 mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f // indirect ) diff --git a/go.sum b/go.sum index 803bd71..f5b54aa 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ 4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs= 4d63.com/gochecknoglobals v0.2.1 h1:1eiorGsgHOFOuoOiJDy2psSrQbRdIHrlge0IJIkUgDc= 4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/4meepo/tagalign v1.3.4 h1:P51VcvBnf04YkHzjfclN6BbsopfJR5rxs1n+5zHt+w8= github.com/4meepo/tagalign v1.3.4/go.mod h1:M+pnkHH2vG8+qhE5bVc/zeP7HS/j910Fwa9TUSyZVI0= github.com/Abirdcfly/dupword v0.1.1 h1:Bsxe0fIw6OwBtXMIncaTxCLHYO5BB+3mcsR5E8VXloY= @@ -22,11 +24,10 @@ github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 h1:/fTUt5vmbkAcMBt4YQiuC github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0/go.mod h1:ONJg5sxcbsdQQ4pOW8TGdTidT2TMAUy/2Xhr8mrYaao= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= -github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= -github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= +github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= +github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= github.com/OpenPeeDeeP/depguard/v2 v2.2.0 h1:vDfG60vDtIuf0MEOhmLlLLSzqaRM8EMcgJPdp74zmpA= github.com/OpenPeeDeeP/depguard/v2 v2.2.0/go.mod h1:CIzddKRvLBC4Au5aYP/i3nyaWQ+ClszLIuVocRiCYFQ= github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk= @@ -45,6 +46,8 @@ github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8ger github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU= github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s= github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI= +github.com/avast/retry-go/v4 v4.6.0 h1:K9xNA+KeB8HHc2aWFuLb25Offp+0iVRXEvFx8IinRJA= +github.com/avast/retry-go/v4 v4.6.0/go.mod h1:gvWlPhBVsvBbLkVGDg/KwvBv0bEkCOLRRSHKIr2PyOE= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bkielbasa/cyclop v1.2.1 h1:AeF71HZDob1P2/pRm1so9cd1alZnrpyc4q2uP2l0gJY= @@ -57,8 +60,8 @@ github.com/breml/bidichk v0.2.7 h1:dAkKQPLl/Qrk7hnP6P+E0xOodrq8Us7+U0o4UBOAlQY= github.com/breml/bidichk v0.2.7/go.mod h1:YodjipAGI9fGcYM7II6wFvGhdMYsC5pHDlGzqvEW3tQ= github.com/breml/errchkjson v0.3.6 h1:VLhVkqSBH96AvXEyclMR37rZslRrY2kcyq+31HCsVrA= github.com/breml/errchkjson v0.3.6/go.mod h1:jhSDoFheAF2RSDOlCfhHO9KqhZgAYLyvHe7bRCX8f/U= -github.com/bufbuild/protocompile v0.14.0 h1:z3DW4IvXE5G/uTOnSQn+qwQQxvhckkTWLS/0No/o7KU= -github.com/bufbuild/protocompile v0.14.0/go.mod h1:N6J1NYzkspJo3ZwyL4Xjvli86XOj1xq4qAasUFxGups= +github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= +github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= github.com/butuzov/ireturn v0.3.0 h1:hTjMqWw3y5JC3kpnC5vXmFJAWI/m31jaCYQqzkS6PL0= github.com/butuzov/ireturn v0.3.0/go.mod h1:A09nIiwiqzN/IoVo9ogpa0Hzi9fex1kd9PSD6edP5ZA= github.com/butuzov/mirror v1.2.0 h1:9YVK1qIjNspaqWutSv8gsge2e/Xpq1eqEkslEUHy5cs= @@ -150,6 +153,9 @@ github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 h1:/1322Qns6BtQxUZDTAT4SdcoxknUki7IAoK4SAXr8ME= @@ -174,9 +180,8 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA= -github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/pprof v0.0.0-20240903155634-a8630aee4ab9 h1:q5g0N9eal4bmJwXHC5z0QCKs8qhS35hFfq0BAYsIwZI= +github.com/google/pprof v0.0.0-20240903155634-a8630aee4ab9/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gordonklaus/ineffassign v0.1.0 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5hwJd0f9s= @@ -193,8 +198,8 @@ github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY= github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU= -github.com/hamba/avro/v2 v2.24.0 h1:axTlaYDkcSY0dVekRSy8cdrsj5MG86WqosUQacKCids= -github.com/hamba/avro/v2 v2.24.0/go.mod h1:7vDfy/2+kYCE8WUHoj2et59GTv0ap7ptktMXu0QHePI= +github.com/hamba/avro/v2 v2.25.2 h1:28dqbOCB7wA/3+J1ZN4GQ40tzsFtbtItkTPWgl97el0= +github.com/hamba/avro/v2 v2.25.2/go.mod h1:I8glyswHnpED3Nlx2ZdUe+4LJnCOOyiCzLMno9i/Uu0= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-plugin v1.6.1 h1:P7MR2UP6gNKGPp+y7EZw2kOiq4IR9WiqLvp0XOsVdwI= @@ -208,10 +213,8 @@ github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= -github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= -github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= +github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jaswdr/faker v1.19.1 h1:xBoz8/O6r0QAR8eEvKJZMdofxiRH+F0M/7MU9eNKhsM= @@ -238,6 +241,8 @@ github.com/kisielk/errcheck v1.7.0 h1:+SbscKmWJ5mOK/bO1zS60F5I9WwZDWOfRsC4RwfwRV github.com/kisielk/errcheck v1.7.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ= github.com/kkHAIKE/contextcheck v1.1.5 h1:CdnJh63tcDe53vG+RebdpdXJTc9atMgGqdx8LXxiilg= github.com/kkHAIKE/contextcheck v1.1.5/go.mod h1:O930cpht4xb1YQpK+1+AgoM3mFsvxr7uyFptcnWTYUA= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -256,6 +261,8 @@ github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSio github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= +github.com/linkedin/goavro/v2 v2.13.0 h1:L8eI8GcuciwUkt41Ej62joSZS4kKaYIUdze+6for9NU= +github.com/linkedin/goavro/v2 v2.13.0/go.mod h1:KXx+erlq+RPlGSPmLF7xGo6SAbh8sCQ53x064+ioxhk= github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCEtOM= github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= github.com/macabu/inamedparam v0.1.3 h1:2tk/phHkMlEL/1GNe/Yf6kkR/hkcUdAEY3L0hjYV1Mk= @@ -282,20 +289,20 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mgechev/revive v1.3.9 h1:18Y3R4a2USSBF+QZKFQwVkBROUda7uoBlkEuBD+YD1A= github.com/mgechev/revive v1.3.9/go.mod h1:+uxEIr5UH0TjXWHTno3xh4u7eg6jDpXKzQccA9UGhHU= -github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -303,6 +310,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI= github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U= github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhKRf3Swg= @@ -336,12 +345,12 @@ github.com/polyfloyd/go-errorlint v1.6.0 h1:tftWV9DE7txiFzPpztTAwyoRLKNj9gpVm2cg github.com/polyfloyd/go-errorlint v1.6.0/go.mod h1:HR7u8wuP1kb1NeN1zqTd1ZMlqUKPPHF+Id4vIPvDqVw= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4= +github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.54.0 h1:ZlZy0BgJhTwVZUn7dLOkwCZHUkrAqd3WYtcFCWnM1D8= -github.com/prometheus/common v0.54.0/go.mod h1:/TQgMJP5CuVYveyT7n/0Ix8yLNNXy9yRSkhnLTHPDIQ= +github.com/prometheus/common v0.59.1 h1:LXb1quJHWm1P6wq/U824uxYi4Sg0oGvNeUm1z5dJoX0= +github.com/prometheus/common v0.59.1/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 h1:+Wl/0aFp0hpuHM3H//KMft64WQ1yX9LdJY64Qm/gFCo= @@ -383,8 +392,8 @@ github.com/securego/gosec/v2 v2.21.2 h1:deZp5zmYf3TWwU7A7cR2+SolbTpZ3HQiwFqnzQyE github.com/securego/gosec/v2 v2.21.2/go.mod h1:au33kg78rNseF5PwPnTWhuYBFf534bvJRvOrgZ/bFzU= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= -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/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= @@ -401,9 +410,8 @@ github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCp github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= -github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -419,13 +427,13 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= @@ -438,8 +446,8 @@ github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= -github.com/tetafro/godot v1.4.17 h1:pGzu+Ye7ZUEFx7LHU0dAKmCOXWsPjl7qA6iMGndsjPs= -github.com/tetafro/godot v1.4.17/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio= +github.com/tetafro/godot v1.4.18 h1:ouX3XGiziKDypbpXqShBfnNLTSjR8r3/HVzrtJ+bHlI= +github.com/tetafro/godot v1.4.18/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio= github.com/timakin/bodyclose v0.0.0-20240125160201-f835fa56326a h1:A6uKudFIfAEpoPdaal3aSqGxBzLyU8TqyXImLwo6dIo= github.com/timakin/bodyclose v0.0.0-20240125160201-f835fa56326a/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460= github.com/timonwong/loggercheck v0.9.4 h1:HKKhqrjcVj8sxL7K77beXh0adEm6DLjV/QOGeMXEVi4= @@ -492,17 +500,16 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= -golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk= -golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/exp/typeparams v0.0.0-20240613232115-7f521ea00fb8 h1:+ZJmEdDFzH5H0CnzOrwgbH3elHctfTecW9X0k2tkn5M= -golang.org/x/exp/typeparams v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20240909161429-701f63a606c0 h1:bVwtbF629Xlyxk6xLQq2TDYmqP0uiWaet5LwRebuY0k= +golang.org/x/exp/typeparams v0.0.0-20240909161429-701f63a606c0/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -620,18 +627,18 @@ golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= -golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= +golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= 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= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= -google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/grpc v1.66.1 h1:hO5qAXR19+/Z44hmvIM4dQFMSYX9XcWsByfoxutBpAM= +google.golang.org/grpc v1.66.1/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/protobuf v1.34.3-0.20240816073751-94ecbc261689 h1:hNwajDgT0MlsxZzlUajZVmUYFpts8/CYe4BSNx503ZE= +google.golang.org/protobuf v1.34.3-0.20240816073751-94ecbc261689/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -640,7 +647,6 @@ gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs= gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/cometd/client.go b/internal/cometd/client.go index 442eb2e..e627c05 100644 --- a/internal/cometd/client.go +++ b/internal/cometd/client.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Meroxa, Inc. and Miquido +// Copyright © 2022 Meroxa, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/internal/cometd/requests/connect.go b/internal/cometd/requests/connect.go index 922ae8f..9b19d37 100644 --- a/internal/cometd/requests/connect.go +++ b/internal/cometd/requests/connect.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Meroxa, Inc. and Miquido +// Copyright © 2022 Meroxa, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/internal/cometd/requests/handshake.go b/internal/cometd/requests/handshake.go index d9f22ba..7d1d587 100644 --- a/internal/cometd/requests/handshake.go +++ b/internal/cometd/requests/handshake.go @@ -18,8 +18,7 @@ import "encoding/json" // HandshakeRequest represents handshake request. // See: https://docs.cometd.org/current7/reference/#_handshake_request -type HandshakeRequest struct { -} +type HandshakeRequest struct{} func (r HandshakeRequest) MarshalJSON() ([]byte, error) { return json.Marshal(map[string]interface{}{ diff --git a/internal/cometd/responses/subscribe_test.go b/internal/cometd/responses/subscribe_test.go index 9005e20..18b1461 100644 --- a/internal/cometd/responses/subscribe_test.go +++ b/internal/cometd/responses/subscribe_test.go @@ -26,7 +26,7 @@ func TestSubscribeResponse_GetSubscriptions(t *testing.T) { fakerInstance := faker.New() t.Run("panics when unsupported type is provided", func(t *testing.T) { - var subscription = fakerInstance.Int() + subscription := fakerInstance.Int() response := SubscribeResponse{ Subscription: subscription, @@ -38,7 +38,7 @@ func TestSubscribeResponse_GetSubscriptions(t *testing.T) { }) t.Run("slice with one element is returned when Subscription is string", func(t *testing.T) { - var subscription = fakerInstance.Lorem().Sentence(3) + subscription := fakerInstance.Lorem().Sentence(3) response := SubscribeResponse{ Subscription: subscription, @@ -51,7 +51,7 @@ func TestSubscribeResponse_GetSubscriptions(t *testing.T) { }) t.Run("slice with all elements is returned when Subscription is slice", func(t *testing.T) { - var subscription = []string{ + subscription := []string{ fakerInstance.Lorem().Sentence(3), fakerInstance.Lorem().Sentence(4), fakerInstance.Lorem().Sentence(5), diff --git a/internal/cometd/responses/unsubscribe_test.go b/internal/cometd/responses/unsubscribe_test.go index 70ce823..1604a78 100644 --- a/internal/cometd/responses/unsubscribe_test.go +++ b/internal/cometd/responses/unsubscribe_test.go @@ -26,7 +26,7 @@ func TestUnsubscribeResponse_GetSubscriptions(t *testing.T) { fakerInstance := faker.New() t.Run("panics when unsupported type is provided", func(t *testing.T) { - var subscription = fakerInstance.Int() + subscription := fakerInstance.Int() response := UnsubscribeResponse{ Subscription: subscription, @@ -38,7 +38,7 @@ func TestUnsubscribeResponse_GetSubscriptions(t *testing.T) { }) t.Run("slice with one element is returned when Subscription is string", func(t *testing.T) { - var subscription = fakerInstance.Lorem().Sentence(3) + subscription := fakerInstance.Lorem().Sentence(3) response := UnsubscribeResponse{ Subscription: subscription, @@ -51,7 +51,7 @@ func TestUnsubscribeResponse_GetSubscriptions(t *testing.T) { }) t.Run("slice with all elements is returned when Subscription is slice", func(t *testing.T) { - var subscription = []string{ + subscription := []string{ fakerInstance.Lorem().Sentence(3), fakerInstance.Lorem().Sentence(4), fakerInstance.Lorem().Sentence(5), diff --git a/internal/cometd/responses/unsuccessful_handshake_test.go b/internal/cometd/responses/unsuccessful_handshake_test.go index 2ea450c..7c3c1ed 100644 --- a/internal/cometd/responses/unsuccessful_handshake_test.go +++ b/internal/cometd/responses/unsuccessful_handshake_test.go @@ -25,7 +25,7 @@ func TestUnsuccessfulHandshakeResponseError_Error(t *testing.T) { fakerInstance := faker.New() t.Run("test", func(t *testing.T) { - var errorDetails = fakerInstance.Lorem().Sentence(6) + errorDetails := fakerInstance.Lorem().Sentence(6) response := UnsuccessfulHandshakeResponseError{ErrorDetails: errorDetails} diff --git a/internal/operation.go b/internal/operation.go index 1fd8b7d..3f2e380 100644 --- a/internal/operation.go +++ b/internal/operation.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Meroxa, Inc. and Miquido +// Copyright © 2022 Meroxa, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/internal/salesforce/oauth/client.go b/internal/salesforce/oauth/client.go index 40fe2a0..3a021e1 100644 --- a/internal/salesforce/oauth/client.go +++ b/internal/salesforce/oauth/client.go @@ -36,7 +36,7 @@ const ( testLoginURI = "https://test.salesforce.com/services/oauth2/token" ) -//go:generate moq -out client_moq_test.go . Client +// skip go:generate moq -out client_moq_test.go . Client. type Client interface { Authenticate(ctx context.Context) (response.TokenResponse, error) } @@ -70,7 +70,7 @@ type DefaultClient struct { securityToken string } -//go:generate moq -out http_client_moq_test.go . httpClient +// skip go:generate moq -out http_client_moq_test.go . httpClient. type httpClient interface { Do(req *http.Request) (*http.Response, error) } diff --git a/internal/salesforce/oauth/http_client_moq_test.go b/internal/salesforce/oauth/http_client_moq_test.go index 17a8263..e8a9c7a 100644 --- a/internal/salesforce/oauth/http_client_moq_test.go +++ b/internal/salesforce/oauth/http_client_moq_test.go @@ -14,19 +14,19 @@ var _ httpClient = &httpClientMock{} // httpClientMock is a mock implementation of httpClient. // -// func TestSomethingThatUseshttpClient(t *testing.T) { +// func TestSomethingThatUseshttpClient(t *testing.T) { // -// // make and configure a mocked httpClient -// mockedhttpClient := &httpClientMock{ -// DoFunc: func(req *http.Request) (*http.Response, error) { -// panic("mock out the Do method") -// }, -// } +// // make and configure a mocked httpClient +// mockedhttpClient := &httpClientMock{ +// DoFunc: func(req *http.Request) (*http.Response, error) { +// panic("mock out the Do method") +// }, +// } // -// // use mockedhttpClient in code that requires httpClient -// // and then make assertions. +// // use mockedhttpClient in code that requires httpClient +// // and then make assertions. // -// } +// } type httpClientMock struct { // DoFunc mocks the Do method. DoFunc func(req *http.Request) (*http.Response, error) @@ -60,7 +60,8 @@ func (mock *httpClientMock) Do(req *http.Request) (*http.Response, error) { // DoCalls gets all the calls that were made to Do. // Check the length with: -// len(mockedhttpClient.DoCalls()) +// +// len(mockedhttpClient.DoCalls()) func (mock *httpClientMock) DoCalls() []struct { Req *http.Request } { diff --git a/internal/salesforce/oauth/response/failure.go b/internal/salesforce/oauth/response/failure.go index e56538a..8042699 100644 --- a/internal/salesforce/oauth/response/failure.go +++ b/internal/salesforce/oauth/response/failure.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Meroxa, Inc. and Miquido +// Copyright © 2022 Meroxa, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/internal/salesforce/oauth/response/failure_test.go b/internal/salesforce/oauth/response/failure_test.go index 518da87..d33222d 100644 --- a/internal/salesforce/oauth/response/failure_test.go +++ b/internal/salesforce/oauth/response/failure_test.go @@ -24,7 +24,7 @@ import ( func TestFailureResponseError_Error(t *testing.T) { fakerInstance := faker.New() - var errorContents = fakerInstance.Lorem().Sentence(6) + errorContents := fakerInstance.Lorem().Sentence(6) failureResponseError := FailureResponseError{ ErrorName: fakerInstance.Lorem().Sentence(3), diff --git a/internal/utils/http_response_decoder_test.go b/internal/utils/http_response_decoder_test.go index 1cf8d21..3322f49 100644 --- a/internal/utils/http_response_decoder_test.go +++ b/internal/utils/http_response_decoder_test.go @@ -44,7 +44,7 @@ func TestDecodeHTTPResponse(t *testing.T) { }) t.Run("fails to read data when reader could not be initialized", func(t *testing.T) { - var errorText = fakerInstance.Lorem().Sentence(6) + errorText := fakerInstance.Lorem().Sentence(6) response := &http.Response{ Body: io.NopCloser(&invalidReader{text: errorText}), @@ -60,7 +60,7 @@ func TestDecodeHTTPResponse(t *testing.T) { }) t.Run("fails to decompress data when reader could not be initialized", func(t *testing.T) { - var errorText = fakerInstance.Lorem().Sentence(6) + errorText := fakerInstance.Lorem().Sentence(6) response := &http.Response{ Body: io.NopCloser(&invalidReader{text: errorText}), @@ -76,7 +76,7 @@ func TestDecodeHTTPResponse(t *testing.T) { }) t.Run("returns raw body when no encoding is specified", func(t *testing.T) { - var bodyValue = fakerInstance.Lorem().Bytes(16) + bodyValue := fakerInstance.Lorem().Bytes(16) response := &http.Response{ Body: io.NopCloser(bytes.NewReader(bodyValue)), @@ -93,7 +93,7 @@ func TestDecodeHTTPResponse(t *testing.T) { t.Run("decompresses and returns body when gzip encoding is specified", func(t *testing.T) { var buff bytes.Buffer - var bodyValue = fakerInstance.Lorem().Bytes(16) + bodyValue := fakerInstance.Lorem().Bytes(16) gz, err := gzip.NewWriterLevel(&buff, gzip.BestSpeed) require.NoError(t, err) diff --git a/proto/buf.gen.yaml b/proto/buf.gen.yaml new file mode 100644 index 0000000..44811d9 --- /dev/null +++ b/proto/buf.gen.yaml @@ -0,0 +1,14 @@ +version: v1 +managed: + enabled: true + go_package_prefix: + default: "github.com/conduitio-labs/conduit-connector-salesforce/proto" +plugins: + - plugin: buf.build/protocolbuffers/go:v1.34.1 + out: . + opt: + - paths=source_relative + - plugin: buf.build/grpc/go:v1.4.0 + out: . + opt: + - paths=source_relative diff --git a/proto/buf.lock b/proto/buf.lock new file mode 100644 index 0000000..c91b581 --- /dev/null +++ b/proto/buf.lock @@ -0,0 +1,2 @@ +# Generated by buf. DO NOT EDIT. +version: v1 diff --git a/proto/buf.yaml b/proto/buf.yaml new file mode 100644 index 0000000..1a51945 --- /dev/null +++ b/proto/buf.yaml @@ -0,0 +1,7 @@ +version: v1 +breaking: + use: + - FILE +lint: + use: + - DEFAULT diff --git a/proto/eventbus/v1/pubsub_api.pb.go b/proto/eventbus/v1/pubsub_api.pb.go new file mode 100644 index 0000000..a5f8993 --- /dev/null +++ b/proto/eventbus/v1/pubsub_api.pb.go @@ -0,0 +1,1864 @@ +// +// Salesforce Pub/Sub API Version 1. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.34.1 +// protoc (unknown) +// source: eventbus/v1/pubsub_api.proto + +package eventbusv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Supported error codes +type ErrorCode int32 + +const ( + ErrorCode_UNKNOWN ErrorCode = 0 + ErrorCode_PUBLISH ErrorCode = 1 + // ErrorCode for unrecoverable commit errors. + ErrorCode_COMMIT ErrorCode = 2 +) + +// Enum value maps for ErrorCode. +var ( + ErrorCode_name = map[int32]string{ + 0: "UNKNOWN", + 1: "PUBLISH", + 2: "COMMIT", + } + ErrorCode_value = map[string]int32{ + "UNKNOWN": 0, + "PUBLISH": 1, + "COMMIT": 2, + } +) + +func (x ErrorCode) Enum() *ErrorCode { + p := new(ErrorCode) + *p = x + return p +} + +func (x ErrorCode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ErrorCode) Descriptor() protoreflect.EnumDescriptor { + return file_eventbus_v1_pubsub_api_proto_enumTypes[0].Descriptor() +} + +func (ErrorCode) Type() protoreflect.EnumType { + return &file_eventbus_v1_pubsub_api_proto_enumTypes[0] +} + +func (x ErrorCode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ErrorCode.Descriptor instead. +func (ErrorCode) EnumDescriptor() ([]byte, []int) { + return file_eventbus_v1_pubsub_api_proto_rawDescGZIP(), []int{0} +} + +// Supported subscription replay start values. +// By default, the subscription will start at the tip of the stream if ReplayPreset is not specified. +type ReplayPreset int32 + +const ( + // Start the subscription at the tip of the stream. + ReplayPreset_LATEST ReplayPreset = 0 + // Start the subscription at the earliest point in the stream. + ReplayPreset_EARLIEST ReplayPreset = 1 + // Start the subscription after a custom point in the stream. This must be set with a valid replay_id in the FetchRequest. + ReplayPreset_CUSTOM ReplayPreset = 2 +) + +// Enum value maps for ReplayPreset. +var ( + ReplayPreset_name = map[int32]string{ + 0: "LATEST", + 1: "EARLIEST", + 2: "CUSTOM", + } + ReplayPreset_value = map[string]int32{ + "LATEST": 0, + "EARLIEST": 1, + "CUSTOM": 2, + } +) + +func (x ReplayPreset) Enum() *ReplayPreset { + p := new(ReplayPreset) + *p = x + return p +} + +func (x ReplayPreset) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ReplayPreset) Descriptor() protoreflect.EnumDescriptor { + return file_eventbus_v1_pubsub_api_proto_enumTypes[1].Descriptor() +} + +func (ReplayPreset) Type() protoreflect.EnumType { + return &file_eventbus_v1_pubsub_api_proto_enumTypes[1] +} + +func (x ReplayPreset) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ReplayPreset.Descriptor instead. +func (ReplayPreset) EnumDescriptor() ([]byte, []int) { + return file_eventbus_v1_pubsub_api_proto_rawDescGZIP(), []int{1} +} + +// Contains information about a topic and uniquely identifies it. TopicInfo is returned by the GetTopic RPC method. +type TopicInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Topic name + TopicName string `protobuf:"bytes,1,opt,name=topic_name,json=topicName,proto3" json:"topic_name,omitempty"` + // Tenant/org GUID + TenantGuid string `protobuf:"bytes,2,opt,name=tenant_guid,json=tenantGuid,proto3" json:"tenant_guid,omitempty"` + // Is publishing allowed? + CanPublish bool `protobuf:"varint,3,opt,name=can_publish,json=canPublish,proto3" json:"can_publish,omitempty"` + // Is subscription allowed? + CanSubscribe bool `protobuf:"varint,4,opt,name=can_subscribe,json=canSubscribe,proto3" json:"can_subscribe,omitempty"` + // ID of the current topic schema, which can be used for + // publishing of generically serialized events. + SchemaId string `protobuf:"bytes,5,opt,name=schema_id,json=schemaId,proto3" json:"schema_id,omitempty"` + // RPC ID used to trace errors. + RpcId string `protobuf:"bytes,6,opt,name=rpc_id,json=rpcId,proto3" json:"rpc_id,omitempty"` +} + +func (x *TopicInfo) Reset() { + *x = TopicInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TopicInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TopicInfo) ProtoMessage() {} + +func (x *TopicInfo) ProtoReflect() protoreflect.Message { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TopicInfo.ProtoReflect.Descriptor instead. +func (*TopicInfo) Descriptor() ([]byte, []int) { + return file_eventbus_v1_pubsub_api_proto_rawDescGZIP(), []int{0} +} + +func (x *TopicInfo) GetTopicName() string { + if x != nil { + return x.TopicName + } + return "" +} + +func (x *TopicInfo) GetTenantGuid() string { + if x != nil { + return x.TenantGuid + } + return "" +} + +func (x *TopicInfo) GetCanPublish() bool { + if x != nil { + return x.CanPublish + } + return false +} + +func (x *TopicInfo) GetCanSubscribe() bool { + if x != nil { + return x.CanSubscribe + } + return false +} + +func (x *TopicInfo) GetSchemaId() string { + if x != nil { + return x.SchemaId + } + return "" +} + +func (x *TopicInfo) GetRpcId() string { + if x != nil { + return x.RpcId + } + return "" +} + +// A request message for GetTopic. Note that the tenant/org is not directly referenced +// in the request, but is implicitly identified by the authentication headers. +type TopicRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The name of the topic to retrieve. + TopicName string `protobuf:"bytes,1,opt,name=topic_name,json=topicName,proto3" json:"topic_name,omitempty"` +} + +func (x *TopicRequest) Reset() { + *x = TopicRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TopicRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TopicRequest) ProtoMessage() {} + +func (x *TopicRequest) ProtoReflect() protoreflect.Message { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TopicRequest.ProtoReflect.Descriptor instead. +func (*TopicRequest) Descriptor() ([]byte, []int) { + return file_eventbus_v1_pubsub_api_proto_rawDescGZIP(), []int{1} +} + +func (x *TopicRequest) GetTopicName() string { + if x != nil { + return x.TopicName + } + return "" +} + +// Reserved for future use. +// Header that contains information for distributed tracing, filtering, routing, etc. +// For example, X-B3-* headers assigned by a publisher are stored with the event and +// can provide a full distributed trace of the event across its entire lifecycle. +type EventHeader struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *EventHeader) Reset() { + *x = EventHeader{} + if protoimpl.UnsafeEnabled { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EventHeader) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EventHeader) ProtoMessage() {} + +func (x *EventHeader) ProtoReflect() protoreflect.Message { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EventHeader.ProtoReflect.Descriptor instead. +func (*EventHeader) Descriptor() ([]byte, []int) { + return file_eventbus_v1_pubsub_api_proto_rawDescGZIP(), []int{2} +} + +func (x *EventHeader) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *EventHeader) GetValue() []byte { + if x != nil { + return x.Value + } + return nil +} + +// Represents an event that an event publishing app creates. +type ProducerEvent struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Either a user-provided ID or a system generated guid + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // Schema fingerprint for this event which is hash of the schema + SchemaId string `protobuf:"bytes,2,opt,name=schema_id,json=schemaId,proto3" json:"schema_id,omitempty"` + // The message data field + Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"` + // Reserved for future use. Key-value pairs of headers. + Headers []*EventHeader `protobuf:"bytes,4,rep,name=headers,proto3" json:"headers,omitempty"` +} + +func (x *ProducerEvent) Reset() { + *x = ProducerEvent{} + if protoimpl.UnsafeEnabled { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ProducerEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProducerEvent) ProtoMessage() {} + +func (x *ProducerEvent) ProtoReflect() protoreflect.Message { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProducerEvent.ProtoReflect.Descriptor instead. +func (*ProducerEvent) Descriptor() ([]byte, []int) { + return file_eventbus_v1_pubsub_api_proto_rawDescGZIP(), []int{3} +} + +func (x *ProducerEvent) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ProducerEvent) GetSchemaId() string { + if x != nil { + return x.SchemaId + } + return "" +} + +func (x *ProducerEvent) GetPayload() []byte { + if x != nil { + return x.Payload + } + return nil +} + +func (x *ProducerEvent) GetHeaders() []*EventHeader { + if x != nil { + return x.Headers + } + return nil +} + +// Represents an event that is consumed in a subscriber client. +// In addition to the fields in ProducerEvent, ConsumerEvent has the replay_id field. +type ConsumerEvent struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The event with fields identical to ProducerEvent + Event *ProducerEvent `protobuf:"bytes,1,opt,name=event,proto3" json:"event,omitempty"` + // The replay ID of the event. + // A subscriber app can store the replay ID. When the app restarts, it can resume subscription + // starting from events in the event bus after the event with that replay ID. + ReplayId []byte `protobuf:"bytes,2,opt,name=replay_id,json=replayId,proto3" json:"replay_id,omitempty"` +} + +func (x *ConsumerEvent) Reset() { + *x = ConsumerEvent{} + if protoimpl.UnsafeEnabled { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ConsumerEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConsumerEvent) ProtoMessage() {} + +func (x *ConsumerEvent) ProtoReflect() protoreflect.Message { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ConsumerEvent.ProtoReflect.Descriptor instead. +func (*ConsumerEvent) Descriptor() ([]byte, []int) { + return file_eventbus_v1_pubsub_api_proto_rawDescGZIP(), []int{4} +} + +func (x *ConsumerEvent) GetEvent() *ProducerEvent { + if x != nil { + return x.Event + } + return nil +} + +func (x *ConsumerEvent) GetReplayId() []byte { + if x != nil { + return x.ReplayId + } + return nil +} + +// Event publish result that the Publish RPC method returns. The result contains replay_id or a publish error. +type PublishResult struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Replay ID of the event + ReplayId []byte `protobuf:"bytes,1,opt,name=replay_id,json=replayId,proto3" json:"replay_id,omitempty"` + // Publish error if any + Error *Error `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` + // Correlation key of the ProducerEvent + CorrelationKey string `protobuf:"bytes,3,opt,name=correlation_key,json=correlationKey,proto3" json:"correlation_key,omitempty"` +} + +func (x *PublishResult) Reset() { + *x = PublishResult{} + if protoimpl.UnsafeEnabled { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PublishResult) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PublishResult) ProtoMessage() {} + +func (x *PublishResult) ProtoReflect() protoreflect.Message { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PublishResult.ProtoReflect.Descriptor instead. +func (*PublishResult) Descriptor() ([]byte, []int) { + return file_eventbus_v1_pubsub_api_proto_rawDescGZIP(), []int{5} +} + +func (x *PublishResult) GetReplayId() []byte { + if x != nil { + return x.ReplayId + } + return nil +} + +func (x *PublishResult) GetError() *Error { + if x != nil { + return x.Error + } + return nil +} + +func (x *PublishResult) GetCorrelationKey() string { + if x != nil { + return x.CorrelationKey + } + return "" +} + +// Contains error information for an error that an RPC method returns. +type Error struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Error code + Code ErrorCode `protobuf:"varint,1,opt,name=code,proto3,enum=eventbus.v1.ErrorCode" json:"code,omitempty"` + // Error message + Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` +} + +func (x *Error) Reset() { + *x = Error{} + if protoimpl.UnsafeEnabled { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Error) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Error) ProtoMessage() {} + +func (x *Error) ProtoReflect() protoreflect.Message { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Error.ProtoReflect.Descriptor instead. +func (*Error) Descriptor() ([]byte, []int) { + return file_eventbus_v1_pubsub_api_proto_rawDescGZIP(), []int{6} +} + +func (x *Error) GetCode() ErrorCode { + if x != nil { + return x.Code + } + return ErrorCode_UNKNOWN +} + +func (x *Error) GetMsg() string { + if x != nil { + return x.Msg + } + return "" +} + +// Request for the Subscribe streaming RPC method. This request is used to: +// 1. Establish the initial subscribe stream. +// 2. Request more events from the subscription stream. +// Flow Control is handled by the subscriber via num_requested. +// A client can specify a starting point for the subscription with replay_preset and replay_id combinations. +// If no replay_preset is specified, the subscription starts at LATEST (tip of the stream). +// replay_preset and replay_id values are only consumed as part of the first FetchRequest. If +// a client needs to start at another point in the stream, it must start a new subscription. +type FetchRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Identifies a topic for subscription in the very first FetchRequest of the stream. The topic cannot change + // in subsequent FetchRequests within the same subscribe stream, but can be omitted for efficiency. + TopicName string `protobuf:"bytes,1,opt,name=topic_name,json=topicName,proto3" json:"topic_name,omitempty"` + // Subscription starting point. This is consumed only as part of the first FetchRequest + // when the subscription is set up. + ReplayPreset ReplayPreset `protobuf:"varint,2,opt,name=replay_preset,json=replayPreset,proto3,enum=eventbus.v1.ReplayPreset" json:"replay_preset,omitempty"` + // If replay_preset of CUSTOM is selected, specify the subscription point to start after. + // This is consumed only as part of the first FetchRequest when the subscription is set up. + ReplayId []byte `protobuf:"bytes,3,opt,name=replay_id,json=replayId,proto3" json:"replay_id,omitempty"` + // Number of events a client is ready to accept. Each subsequent FetchRequest informs the server + // of additional processing capacity available on the client side. There is no guarantee of equal number of + // FetchResponse messages to be sent back. There is not necessarily a correspondence between + // number of requested events in FetchRequest and the number of events returned in subsequent + // FetchResponses. + NumRequested int32 `protobuf:"varint,4,opt,name=num_requested,json=numRequested,proto3" json:"num_requested,omitempty"` + // For internal Salesforce use only. + AuthRefresh string `protobuf:"bytes,5,opt,name=auth_refresh,json=authRefresh,proto3" json:"auth_refresh,omitempty"` +} + +func (x *FetchRequest) Reset() { + *x = FetchRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FetchRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FetchRequest) ProtoMessage() {} + +func (x *FetchRequest) ProtoReflect() protoreflect.Message { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FetchRequest.ProtoReflect.Descriptor instead. +func (*FetchRequest) Descriptor() ([]byte, []int) { + return file_eventbus_v1_pubsub_api_proto_rawDescGZIP(), []int{7} +} + +func (x *FetchRequest) GetTopicName() string { + if x != nil { + return x.TopicName + } + return "" +} + +func (x *FetchRequest) GetReplayPreset() ReplayPreset { + if x != nil { + return x.ReplayPreset + } + return ReplayPreset_LATEST +} + +func (x *FetchRequest) GetReplayId() []byte { + if x != nil { + return x.ReplayId + } + return nil +} + +func (x *FetchRequest) GetNumRequested() int32 { + if x != nil { + return x.NumRequested + } + return 0 +} + +func (x *FetchRequest) GetAuthRefresh() string { + if x != nil { + return x.AuthRefresh + } + return "" +} + +// Response for the Subscribe streaming RPC method. This returns ConsumerEvent(s). +// If there are no events to deliver, the server sends an empty batch fetch response with the latest replay ID. The +// empty fetch response is sent within 270 seconds. An empty fetch response provides a periodic keepalive from the +// server and the latest replay ID. +type FetchResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Received events for subscription for client consumption + Events []*ConsumerEvent `protobuf:"bytes,1,rep,name=events,proto3" json:"events,omitempty"` + // Latest replay ID of a subscription. Enables clients with an updated replay value so that they can keep track + // of their last consumed replay. Clients will not have to start a subscription at a very old replay in the case where a resubscribe is necessary. + LatestReplayId []byte `protobuf:"bytes,2,opt,name=latest_replay_id,json=latestReplayId,proto3" json:"latest_replay_id,omitempty"` + // RPC ID used to trace errors. + RpcId string `protobuf:"bytes,3,opt,name=rpc_id,json=rpcId,proto3" json:"rpc_id,omitempty"` + // Number of remaining events to be delivered to the client for a Subscribe RPC call. + PendingNumRequested int32 `protobuf:"varint,4,opt,name=pending_num_requested,json=pendingNumRequested,proto3" json:"pending_num_requested,omitempty"` +} + +func (x *FetchResponse) Reset() { + *x = FetchResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FetchResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FetchResponse) ProtoMessage() {} + +func (x *FetchResponse) ProtoReflect() protoreflect.Message { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FetchResponse.ProtoReflect.Descriptor instead. +func (*FetchResponse) Descriptor() ([]byte, []int) { + return file_eventbus_v1_pubsub_api_proto_rawDescGZIP(), []int{8} +} + +func (x *FetchResponse) GetEvents() []*ConsumerEvent { + if x != nil { + return x.Events + } + return nil +} + +func (x *FetchResponse) GetLatestReplayId() []byte { + if x != nil { + return x.LatestReplayId + } + return nil +} + +func (x *FetchResponse) GetRpcId() string { + if x != nil { + return x.RpcId + } + return "" +} + +func (x *FetchResponse) GetPendingNumRequested() int32 { + if x != nil { + return x.PendingNumRequested + } + return 0 +} + +// Request for the GetSchema RPC method. The schema request is based on the event schema ID. +type SchemaRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Schema fingerprint for this event, which is a hash of the schema. + SchemaId string `protobuf:"bytes,1,opt,name=schema_id,json=schemaId,proto3" json:"schema_id,omitempty"` +} + +func (x *SchemaRequest) Reset() { + *x = SchemaRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SchemaRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SchemaRequest) ProtoMessage() {} + +func (x *SchemaRequest) ProtoReflect() protoreflect.Message { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SchemaRequest.ProtoReflect.Descriptor instead. +func (*SchemaRequest) Descriptor() ([]byte, []int) { + return file_eventbus_v1_pubsub_api_proto_rawDescGZIP(), []int{9} +} + +func (x *SchemaRequest) GetSchemaId() string { + if x != nil { + return x.SchemaId + } + return "" +} + +// Response for the GetSchema RPC method. This returns the schema ID and schema of an event. +type SchemaInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Avro schema in JSON format + SchemaJson string `protobuf:"bytes,1,opt,name=schema_json,json=schemaJson,proto3" json:"schema_json,omitempty"` + // Schema fingerprint + SchemaId string `protobuf:"bytes,2,opt,name=schema_id,json=schemaId,proto3" json:"schema_id,omitempty"` + // RPC ID used to trace errors. + RpcId string `protobuf:"bytes,3,opt,name=rpc_id,json=rpcId,proto3" json:"rpc_id,omitempty"` +} + +func (x *SchemaInfo) Reset() { + *x = SchemaInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SchemaInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SchemaInfo) ProtoMessage() {} + +func (x *SchemaInfo) ProtoReflect() protoreflect.Message { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SchemaInfo.ProtoReflect.Descriptor instead. +func (*SchemaInfo) Descriptor() ([]byte, []int) { + return file_eventbus_v1_pubsub_api_proto_rawDescGZIP(), []int{10} +} + +func (x *SchemaInfo) GetSchemaJson() string { + if x != nil { + return x.SchemaJson + } + return "" +} + +func (x *SchemaInfo) GetSchemaId() string { + if x != nil { + return x.SchemaId + } + return "" +} + +func (x *SchemaInfo) GetRpcId() string { + if x != nil { + return x.RpcId + } + return "" +} + +// Request for the Publish and PublishStream RPC method. +type PublishRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Topic to publish on + TopicName string `protobuf:"bytes,1,opt,name=topic_name,json=topicName,proto3" json:"topic_name,omitempty"` + // Batch of ProducerEvent(s) to send + Events []*ProducerEvent `protobuf:"bytes,2,rep,name=events,proto3" json:"events,omitempty"` + // For internal Salesforce use only. + AuthRefresh string `protobuf:"bytes,3,opt,name=auth_refresh,json=authRefresh,proto3" json:"auth_refresh,omitempty"` +} + +func (x *PublishRequest) Reset() { + *x = PublishRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PublishRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PublishRequest) ProtoMessage() {} + +func (x *PublishRequest) ProtoReflect() protoreflect.Message { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PublishRequest.ProtoReflect.Descriptor instead. +func (*PublishRequest) Descriptor() ([]byte, []int) { + return file_eventbus_v1_pubsub_api_proto_rawDescGZIP(), []int{11} +} + +func (x *PublishRequest) GetTopicName() string { + if x != nil { + return x.TopicName + } + return "" +} + +func (x *PublishRequest) GetEvents() []*ProducerEvent { + if x != nil { + return x.Events + } + return nil +} + +func (x *PublishRequest) GetAuthRefresh() string { + if x != nil { + return x.AuthRefresh + } + return "" +} + +// Response for the Publish and PublishStream RPC methods. This returns +// a list of PublishResults for each event that the client attempted to +// publish. PublishResult indicates if publish succeeded or not +// for each event. It also returns the schema ID that was used to create +// the ProducerEvents in the PublishRequest. +type PublishResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Publish results + Results []*PublishResult `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"` + // Schema fingerprint for this event, which is a hash of the schema + SchemaId string `protobuf:"bytes,2,opt,name=schema_id,json=schemaId,proto3" json:"schema_id,omitempty"` + // RPC ID used to trace errors. + RpcId string `protobuf:"bytes,3,opt,name=rpc_id,json=rpcId,proto3" json:"rpc_id,omitempty"` +} + +func (x *PublishResponse) Reset() { + *x = PublishResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PublishResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PublishResponse) ProtoMessage() {} + +func (x *PublishResponse) ProtoReflect() protoreflect.Message { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PublishResponse.ProtoReflect.Descriptor instead. +func (*PublishResponse) Descriptor() ([]byte, []int) { + return file_eventbus_v1_pubsub_api_proto_rawDescGZIP(), []int{12} +} + +func (x *PublishResponse) GetResults() []*PublishResult { + if x != nil { + return x.Results + } + return nil +} + +func (x *PublishResponse) GetSchemaId() string { + if x != nil { + return x.SchemaId + } + return "" +} + +func (x *PublishResponse) GetRpcId() string { + if x != nil { + return x.RpcId + } + return "" +} + +// This feature is part of an open beta release and is subject to the applicable +// Beta Services Terms provided at Agreements and Terms +// (https://www.salesforce.com/company/legal/agreements/). +// +// Request for the ManagedSubscribe streaming RPC method. This request is used to: +// 1. Establish the initial managed subscribe stream. +// 2. Request more events from the subscription stream. +// 3. Commit a Replay ID using CommitReplayRequest. +type ManagedFetchRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Managed subscription ID or developer name. This value corresponds to the + // ID or developer name of the ManagedEventSubscription Tooling API record. + // This value is consumed as part of the first ManagedFetchRequest only. + // The subscription_id cannot change in subsequent ManagedFetchRequests + // within the same subscribe stream, but can be omitted for efficiency. + SubscriptionId string `protobuf:"bytes,1,opt,name=subscription_id,json=subscriptionId,proto3" json:"subscription_id,omitempty"` + DeveloperName string `protobuf:"bytes,2,opt,name=developer_name,json=developerName,proto3" json:"developer_name,omitempty"` + // Number of events a client is ready to accept. Each subsequent FetchRequest informs the server + // of additional processing capacity available on the client side. There is no guarantee of equal number of + // FetchResponse messages to be sent back. There is not necessarily a correspondence between + // number of requested events in FetchRequest and the number of events returned in subsequent + // FetchResponses. + NumRequested int32 `protobuf:"varint,3,opt,name=num_requested,json=numRequested,proto3" json:"num_requested,omitempty"` + // For internal Salesforce use only. + AuthRefresh string `protobuf:"bytes,4,opt,name=auth_refresh,json=authRefresh,proto3" json:"auth_refresh,omitempty"` + CommitReplayIdRequest *CommitReplayRequest `protobuf:"bytes,5,opt,name=commit_replay_id_request,json=commitReplayIdRequest,proto3" json:"commit_replay_id_request,omitempty"` +} + +func (x *ManagedFetchRequest) Reset() { + *x = ManagedFetchRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ManagedFetchRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ManagedFetchRequest) ProtoMessage() {} + +func (x *ManagedFetchRequest) ProtoReflect() protoreflect.Message { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ManagedFetchRequest.ProtoReflect.Descriptor instead. +func (*ManagedFetchRequest) Descriptor() ([]byte, []int) { + return file_eventbus_v1_pubsub_api_proto_rawDescGZIP(), []int{13} +} + +func (x *ManagedFetchRequest) GetSubscriptionId() string { + if x != nil { + return x.SubscriptionId + } + return "" +} + +func (x *ManagedFetchRequest) GetDeveloperName() string { + if x != nil { + return x.DeveloperName + } + return "" +} + +func (x *ManagedFetchRequest) GetNumRequested() int32 { + if x != nil { + return x.NumRequested + } + return 0 +} + +func (x *ManagedFetchRequest) GetAuthRefresh() string { + if x != nil { + return x.AuthRefresh + } + return "" +} + +func (x *ManagedFetchRequest) GetCommitReplayIdRequest() *CommitReplayRequest { + if x != nil { + return x.CommitReplayIdRequest + } + return nil +} + +// This feature is part of an open beta release and is subject to the applicable +// Beta Services Terms provided at Agreements and Terms +// (https://www.salesforce.com/company/legal/agreements/). +// +// Response for the ManagedSubscribe streaming RPC method. This can return +// ConsumerEvent(s) or CommitReplayResponse along with other metadata. +type ManagedFetchResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Received events for subscription for client consumption + Events []*ConsumerEvent `protobuf:"bytes,1,rep,name=events,proto3" json:"events,omitempty"` + // Latest replay ID of a subscription. + LatestReplayId []byte `protobuf:"bytes,2,opt,name=latest_replay_id,json=latestReplayId,proto3" json:"latest_replay_id,omitempty"` + // RPC ID used to trace errors. + RpcId string `protobuf:"bytes,3,opt,name=rpc_id,json=rpcId,proto3" json:"rpc_id,omitempty"` + // Number of remaining events to be delivered to the client for a Subscribe RPC call. + PendingNumRequested int32 `protobuf:"varint,4,opt,name=pending_num_requested,json=pendingNumRequested,proto3" json:"pending_num_requested,omitempty"` + // commit response + CommitResponse *CommitReplayResponse `protobuf:"bytes,5,opt,name=commit_response,json=commitResponse,proto3" json:"commit_response,omitempty"` +} + +func (x *ManagedFetchResponse) Reset() { + *x = ManagedFetchResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ManagedFetchResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ManagedFetchResponse) ProtoMessage() {} + +func (x *ManagedFetchResponse) ProtoReflect() protoreflect.Message { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ManagedFetchResponse.ProtoReflect.Descriptor instead. +func (*ManagedFetchResponse) Descriptor() ([]byte, []int) { + return file_eventbus_v1_pubsub_api_proto_rawDescGZIP(), []int{14} +} + +func (x *ManagedFetchResponse) GetEvents() []*ConsumerEvent { + if x != nil { + return x.Events + } + return nil +} + +func (x *ManagedFetchResponse) GetLatestReplayId() []byte { + if x != nil { + return x.LatestReplayId + } + return nil +} + +func (x *ManagedFetchResponse) GetRpcId() string { + if x != nil { + return x.RpcId + } + return "" +} + +func (x *ManagedFetchResponse) GetPendingNumRequested() int32 { + if x != nil { + return x.PendingNumRequested + } + return 0 +} + +func (x *ManagedFetchResponse) GetCommitResponse() *CommitReplayResponse { + if x != nil { + return x.CommitResponse + } + return nil +} + +// This feature is part of an open beta release and is subject to the applicable +// Beta Services Terms provided at Agreements and Terms +// (https://www.salesforce.com/company/legal/agreements/). +// +// Request to commit a Replay ID for the last processed event or for the latest +// replay ID received in an empty batch of events. +type CommitReplayRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // commit_request_id to identify commit responses + CommitRequestId string `protobuf:"bytes,1,opt,name=commit_request_id,json=commitRequestId,proto3" json:"commit_request_id,omitempty"` + // replayId to commit + ReplayId []byte `protobuf:"bytes,2,opt,name=replay_id,json=replayId,proto3" json:"replay_id,omitempty"` +} + +func (x *CommitReplayRequest) Reset() { + *x = CommitReplayRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommitReplayRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommitReplayRequest) ProtoMessage() {} + +func (x *CommitReplayRequest) ProtoReflect() protoreflect.Message { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommitReplayRequest.ProtoReflect.Descriptor instead. +func (*CommitReplayRequest) Descriptor() ([]byte, []int) { + return file_eventbus_v1_pubsub_api_proto_rawDescGZIP(), []int{15} +} + +func (x *CommitReplayRequest) GetCommitRequestId() string { + if x != nil { + return x.CommitRequestId + } + return "" +} + +func (x *CommitReplayRequest) GetReplayId() []byte { + if x != nil { + return x.ReplayId + } + return nil +} + +// This feature is part of an open beta release and is subject to the applicable +// Beta Services Terms provided at Agreements and Terms +// (https://www.salesforce.com/company/legal/agreements/). +// +// There is no guaranteed 1:1 CommitReplayRequest to CommitReplayResponse. +// N CommitReplayRequest(s) can get compressed in a batch resulting in a single +// CommitReplayResponse which reflects the latest values of last +// CommitReplayRequest in that batch. +type CommitReplayResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // commit_request_id to identify commit responses. + CommitRequestId string `protobuf:"bytes,1,opt,name=commit_request_id,json=commitRequestId,proto3" json:"commit_request_id,omitempty"` + // replayId that may have been committed + ReplayId []byte `protobuf:"bytes,2,opt,name=replay_id,json=replayId,proto3" json:"replay_id,omitempty"` + // for failed commits + Error *Error `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` + // time when server received request in epoch ms + ProcessTime int64 `protobuf:"varint,4,opt,name=process_time,json=processTime,proto3" json:"process_time,omitempty"` +} + +func (x *CommitReplayResponse) Reset() { + *x = CommitReplayResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommitReplayResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommitReplayResponse) ProtoMessage() {} + +func (x *CommitReplayResponse) ProtoReflect() protoreflect.Message { + mi := &file_eventbus_v1_pubsub_api_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommitReplayResponse.ProtoReflect.Descriptor instead. +func (*CommitReplayResponse) Descriptor() ([]byte, []int) { + return file_eventbus_v1_pubsub_api_proto_rawDescGZIP(), []int{16} +} + +func (x *CommitReplayResponse) GetCommitRequestId() string { + if x != nil { + return x.CommitRequestId + } + return "" +} + +func (x *CommitReplayResponse) GetReplayId() []byte { + if x != nil { + return x.ReplayId + } + return nil +} + +func (x *CommitReplayResponse) GetError() *Error { + if x != nil { + return x.Error + } + return nil +} + +func (x *CommitReplayResponse) GetProcessTime() int64 { + if x != nil { + return x.ProcessTime + } + return 0 +} + +var File_eventbus_v1_pubsub_api_proto protoreflect.FileDescriptor + +var file_eventbus_v1_pubsub_api_proto_rawDesc = []byte{ + 0x0a, 0x1c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x75, + 0x62, 0x73, 0x75, 0x62, 0x5f, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x22, 0xc5, 0x01, 0x0a, 0x09, + 0x54, 0x6f, 0x70, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x70, + 0x69, 0x63, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, + 0x6f, 0x70, 0x69, 0x63, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x65, 0x6e, 0x61, + 0x6e, 0x74, 0x5f, 0x67, 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, + 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x47, 0x75, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x61, 0x6e, + 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, + 0x63, 0x61, 0x6e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x61, + 0x6e, 0x5f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0c, 0x63, 0x61, 0x6e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, + 0x1b, 0x0a, 0x09, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, + 0x72, 0x70, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x72, 0x70, + 0x63, 0x49, 0x64, 0x22, 0x2d, 0x0a, 0x0c, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x4e, 0x61, + 0x6d, 0x65, 0x22, 0x35, 0x0a, 0x0b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x8a, 0x01, 0x0a, 0x0d, 0x50, 0x72, + 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x73, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x12, 0x32, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x2e, 0x76, + 0x31, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x07, 0x68, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0x5e, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, + 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x70, + 0x6c, 0x61, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, + 0x70, 0x6c, 0x61, 0x79, 0x49, 0x64, 0x22, 0x7f, 0x0a, 0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, + 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x70, 0x6c, 0x61, + 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, 0x70, 0x6c, + 0x61, 0x79, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x2e, 0x76, + 0x31, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x27, + 0x0a, 0x0f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, + 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x22, 0x45, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x12, 0x2a, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, + 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x72, 0x72, + 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, + 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x22, 0xd2, + 0x01, 0x0a, 0x0c, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3e, + 0x0a, 0x0d, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x50, 0x72, 0x65, 0x73, 0x65, 0x74, + 0x52, 0x0c, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x50, 0x72, 0x65, 0x73, 0x65, 0x74, 0x12, 0x1b, + 0x0a, 0x09, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x08, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x6e, + 0x75, 0x6d, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, + 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x75, 0x74, 0x68, 0x52, 0x65, 0x66, 0x72, + 0x65, 0x73, 0x68, 0x22, 0xb8, 0x01, 0x0a, 0x0d, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x6c, 0x61, 0x74, + 0x65, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x61, + 0x79, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x72, 0x70, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x72, 0x70, 0x63, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x70, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x4e, 0x75, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x22, 0x2c, + 0x0a, 0x0d, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x1b, 0x0a, 0x09, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x49, 0x64, 0x22, 0x61, 0x0a, 0x0a, + 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4a, 0x73, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x73, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x72, 0x70, 0x63, 0x5f, + 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x72, 0x70, 0x63, 0x49, 0x64, 0x22, + 0x86, 0x01, 0x0a, 0x0e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x32, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x72, 0x65, + 0x66, 0x72, 0x65, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x75, 0x74, + 0x68, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x22, 0x7b, 0x0a, 0x0f, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x07, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x49, 0x64, 0x12, 0x15, + 0x0a, 0x06, 0x72, 0x70, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x72, 0x70, 0x63, 0x49, 0x64, 0x22, 0x88, 0x02, 0x0a, 0x13, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x64, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, + 0x0f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x6f, + 0x70, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x64, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, + 0x0d, 0x6e, 0x75, 0x6d, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, + 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x75, 0x74, 0x68, 0x52, 0x65, + 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x59, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, + 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x69, 0x64, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, + 0x75, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x70, 0x6c, + 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x15, 0x63, 0x6f, 0x6d, 0x6d, 0x69, + 0x74, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x22, 0x8b, 0x02, 0x0a, 0x14, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x46, 0x65, 0x74, 0x63, + 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x06, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x62, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x28, 0x0a, + 0x10, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x52, + 0x65, 0x70, 0x6c, 0x61, 0x79, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x72, 0x70, 0x63, 0x5f, 0x69, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x72, 0x70, 0x63, 0x49, 0x64, 0x12, 0x32, + 0x0a, 0x15, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x70, + 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4e, 0x75, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x65, 0x64, 0x12, 0x4a, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x72, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0e, + 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5e, + 0x0a, 0x13, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, + 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x49, 0x64, 0x22, 0xac, + 0x01, 0x0a, 0x14, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x6d, 0x69, + 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x49, 0x64, + 0x12, 0x28, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x12, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x72, + 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, + 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x54, 0x69, 0x6d, 0x65, 0x2a, 0x31, 0x0a, + 0x09, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, + 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x55, 0x42, 0x4c, 0x49, + 0x53, 0x48, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x10, 0x02, + 0x2a, 0x34, 0x0a, 0x0c, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x50, 0x72, 0x65, 0x73, 0x65, 0x74, + 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x41, 0x54, 0x45, 0x53, 0x54, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, + 0x45, 0x41, 0x52, 0x4c, 0x49, 0x45, 0x53, 0x54, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x55, + 0x53, 0x54, 0x4f, 0x4d, 0x10, 0x02, 0x32, 0xc4, 0x03, 0x0a, 0x06, 0x50, 0x75, 0x62, 0x53, 0x75, + 0x62, 0x12, 0x46, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x19, + 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x65, 0x74, + 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x62, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x40, 0x0a, 0x09, 0x47, 0x65, 0x74, + 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x1a, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x08, 0x47, + 0x65, 0x74, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x19, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, + 0x75, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x2e, 0x76, 0x31, + 0x2e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x44, 0x0a, 0x07, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12, 0x1b, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x2e, 0x76, 0x31, + 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x4e, 0x0a, 0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x53, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x12, 0x1b, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, + 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, + 0x12, 0x5b, 0x0a, 0x10, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x53, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x62, 0x65, 0x12, 0x20, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x46, 0x65, 0x74, 0x63, + 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0xc3, 0x01, + 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x2e, 0x76, + 0x31, 0x42, 0x0e, 0x50, 0x75, 0x62, 0x73, 0x75, 0x62, 0x41, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x50, 0x01, 0x5a, 0x53, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x63, 0x6f, 0x6e, 0x64, 0x75, 0x69, 0x74, 0x69, 0x6f, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x63, + 0x6f, 0x6e, 0x64, 0x75, 0x69, 0x74, 0x2d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, + 0x2d, 0x73, 0x61, 0x6c, 0x65, 0x73, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x45, 0x58, 0x58, 0xaa, 0x02, + 0x0b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0b, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x17, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x62, 0x75, 0x73, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x75, 0x73, 0x3a, + 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_eventbus_v1_pubsub_api_proto_rawDescOnce sync.Once + file_eventbus_v1_pubsub_api_proto_rawDescData = file_eventbus_v1_pubsub_api_proto_rawDesc +) + +func file_eventbus_v1_pubsub_api_proto_rawDescGZIP() []byte { + file_eventbus_v1_pubsub_api_proto_rawDescOnce.Do(func() { + file_eventbus_v1_pubsub_api_proto_rawDescData = protoimpl.X.CompressGZIP(file_eventbus_v1_pubsub_api_proto_rawDescData) + }) + return file_eventbus_v1_pubsub_api_proto_rawDescData +} + +var file_eventbus_v1_pubsub_api_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_eventbus_v1_pubsub_api_proto_msgTypes = make([]protoimpl.MessageInfo, 17) +var file_eventbus_v1_pubsub_api_proto_goTypes = []interface{}{ + (ErrorCode)(0), // 0: eventbus.v1.ErrorCode + (ReplayPreset)(0), // 1: eventbus.v1.ReplayPreset + (*TopicInfo)(nil), // 2: eventbus.v1.TopicInfo + (*TopicRequest)(nil), // 3: eventbus.v1.TopicRequest + (*EventHeader)(nil), // 4: eventbus.v1.EventHeader + (*ProducerEvent)(nil), // 5: eventbus.v1.ProducerEvent + (*ConsumerEvent)(nil), // 6: eventbus.v1.ConsumerEvent + (*PublishResult)(nil), // 7: eventbus.v1.PublishResult + (*Error)(nil), // 8: eventbus.v1.Error + (*FetchRequest)(nil), // 9: eventbus.v1.FetchRequest + (*FetchResponse)(nil), // 10: eventbus.v1.FetchResponse + (*SchemaRequest)(nil), // 11: eventbus.v1.SchemaRequest + (*SchemaInfo)(nil), // 12: eventbus.v1.SchemaInfo + (*PublishRequest)(nil), // 13: eventbus.v1.PublishRequest + (*PublishResponse)(nil), // 14: eventbus.v1.PublishResponse + (*ManagedFetchRequest)(nil), // 15: eventbus.v1.ManagedFetchRequest + (*ManagedFetchResponse)(nil), // 16: eventbus.v1.ManagedFetchResponse + (*CommitReplayRequest)(nil), // 17: eventbus.v1.CommitReplayRequest + (*CommitReplayResponse)(nil), // 18: eventbus.v1.CommitReplayResponse +} +var file_eventbus_v1_pubsub_api_proto_depIdxs = []int32{ + 4, // 0: eventbus.v1.ProducerEvent.headers:type_name -> eventbus.v1.EventHeader + 5, // 1: eventbus.v1.ConsumerEvent.event:type_name -> eventbus.v1.ProducerEvent + 8, // 2: eventbus.v1.PublishResult.error:type_name -> eventbus.v1.Error + 0, // 3: eventbus.v1.Error.code:type_name -> eventbus.v1.ErrorCode + 1, // 4: eventbus.v1.FetchRequest.replay_preset:type_name -> eventbus.v1.ReplayPreset + 6, // 5: eventbus.v1.FetchResponse.events:type_name -> eventbus.v1.ConsumerEvent + 5, // 6: eventbus.v1.PublishRequest.events:type_name -> eventbus.v1.ProducerEvent + 7, // 7: eventbus.v1.PublishResponse.results:type_name -> eventbus.v1.PublishResult + 17, // 8: eventbus.v1.ManagedFetchRequest.commit_replay_id_request:type_name -> eventbus.v1.CommitReplayRequest + 6, // 9: eventbus.v1.ManagedFetchResponse.events:type_name -> eventbus.v1.ConsumerEvent + 18, // 10: eventbus.v1.ManagedFetchResponse.commit_response:type_name -> eventbus.v1.CommitReplayResponse + 8, // 11: eventbus.v1.CommitReplayResponse.error:type_name -> eventbus.v1.Error + 9, // 12: eventbus.v1.PubSub.Subscribe:input_type -> eventbus.v1.FetchRequest + 11, // 13: eventbus.v1.PubSub.GetSchema:input_type -> eventbus.v1.SchemaRequest + 3, // 14: eventbus.v1.PubSub.GetTopic:input_type -> eventbus.v1.TopicRequest + 13, // 15: eventbus.v1.PubSub.Publish:input_type -> eventbus.v1.PublishRequest + 13, // 16: eventbus.v1.PubSub.PublishStream:input_type -> eventbus.v1.PublishRequest + 15, // 17: eventbus.v1.PubSub.ManagedSubscribe:input_type -> eventbus.v1.ManagedFetchRequest + 10, // 18: eventbus.v1.PubSub.Subscribe:output_type -> eventbus.v1.FetchResponse + 12, // 19: eventbus.v1.PubSub.GetSchema:output_type -> eventbus.v1.SchemaInfo + 2, // 20: eventbus.v1.PubSub.GetTopic:output_type -> eventbus.v1.TopicInfo + 14, // 21: eventbus.v1.PubSub.Publish:output_type -> eventbus.v1.PublishResponse + 14, // 22: eventbus.v1.PubSub.PublishStream:output_type -> eventbus.v1.PublishResponse + 16, // 23: eventbus.v1.PubSub.ManagedSubscribe:output_type -> eventbus.v1.ManagedFetchResponse + 18, // [18:24] is the sub-list for method output_type + 12, // [12:18] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name +} + +func init() { file_eventbus_v1_pubsub_api_proto_init() } +func file_eventbus_v1_pubsub_api_proto_init() { + if File_eventbus_v1_pubsub_api_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_eventbus_v1_pubsub_api_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TopicInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventbus_v1_pubsub_api_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TopicRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventbus_v1_pubsub_api_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EventHeader); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventbus_v1_pubsub_api_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ProducerEvent); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventbus_v1_pubsub_api_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ConsumerEvent); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventbus_v1_pubsub_api_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PublishResult); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventbus_v1_pubsub_api_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Error); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventbus_v1_pubsub_api_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FetchRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventbus_v1_pubsub_api_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FetchResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventbus_v1_pubsub_api_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SchemaRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventbus_v1_pubsub_api_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SchemaInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventbus_v1_pubsub_api_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PublishRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventbus_v1_pubsub_api_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PublishResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventbus_v1_pubsub_api_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ManagedFetchRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventbus_v1_pubsub_api_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ManagedFetchResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventbus_v1_pubsub_api_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommitReplayRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventbus_v1_pubsub_api_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommitReplayResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_eventbus_v1_pubsub_api_proto_rawDesc, + NumEnums: 2, + NumMessages: 17, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_eventbus_v1_pubsub_api_proto_goTypes, + DependencyIndexes: file_eventbus_v1_pubsub_api_proto_depIdxs, + EnumInfos: file_eventbus_v1_pubsub_api_proto_enumTypes, + MessageInfos: file_eventbus_v1_pubsub_api_proto_msgTypes, + }.Build() + File_eventbus_v1_pubsub_api_proto = out.File + file_eventbus_v1_pubsub_api_proto_rawDesc = nil + file_eventbus_v1_pubsub_api_proto_goTypes = nil + file_eventbus_v1_pubsub_api_proto_depIdxs = nil +} diff --git a/proto/eventbus/v1/pubsub_api.proto b/proto/eventbus/v1/pubsub_api.proto new file mode 100644 index 0000000..0152e77 --- /dev/null +++ b/proto/eventbus/v1/pubsub_api.proto @@ -0,0 +1,413 @@ +/* + * Salesforce Pub/Sub API Version 1. + */ + + syntax = "proto3"; + package eventbus.v1; + + option java_multiple_files = true; + option java_package = "com.salesforce.eventbus.protobuf"; + option java_outer_classname = "PubSubProto"; + + option go_package = "github.com/developerforce/pub-sub-api/go/proto"; + + /* + * Contains information about a topic and uniquely identifies it. TopicInfo is returned by the GetTopic RPC method. + */ + message TopicInfo { + // Topic name + string topic_name = 1; + // Tenant/org GUID + string tenant_guid = 2; + // Is publishing allowed? + bool can_publish = 3; + // Is subscription allowed? + bool can_subscribe = 4; + /* ID of the current topic schema, which can be used for + * publishing of generically serialized events. + */ + string schema_id = 5; + // RPC ID used to trace errors. + string rpc_id = 6; + } + + /* + * A request message for GetTopic. Note that the tenant/org is not directly referenced + * in the request, but is implicitly identified by the authentication headers. + */ + message TopicRequest { + // The name of the topic to retrieve. + string topic_name = 1; + } + + /* + * Reserved for future use. + * Header that contains information for distributed tracing, filtering, routing, etc. + * For example, X-B3-* headers assigned by a publisher are stored with the event and + * can provide a full distributed trace of the event across its entire lifecycle. + */ + message EventHeader { + string key = 1; + bytes value = 2; + } + + /* + * Represents an event that an event publishing app creates. + */ + message ProducerEvent { + // Either a user-provided ID or a system generated guid + string id = 1; + // Schema fingerprint for this event which is hash of the schema + string schema_id = 2; + // The message data field + bytes payload = 3; + // Reserved for future use. Key-value pairs of headers. + repeated EventHeader headers = 4; + } + + /* + * Represents an event that is consumed in a subscriber client. + * In addition to the fields in ProducerEvent, ConsumerEvent has the replay_id field. + */ + message ConsumerEvent { + // The event with fields identical to ProducerEvent + ProducerEvent event = 1; + /* The replay ID of the event. + * A subscriber app can store the replay ID. When the app restarts, it can resume subscription + * starting from events in the event bus after the event with that replay ID. + */ + bytes replay_id = 2; + } + + /* + * Event publish result that the Publish RPC method returns. The result contains replay_id or a publish error. + */ + message PublishResult { + // Replay ID of the event + bytes replay_id = 1; + // Publish error if any + Error error = 2; + // Correlation key of the ProducerEvent + string correlation_key = 3; + } + + // Contains error information for an error that an RPC method returns. + message Error { + // Error code + ErrorCode code = 1; + // Error message + string msg = 2; + } + + // Supported error codes + enum ErrorCode { + UNKNOWN = 0; + PUBLISH = 1; + // ErrorCode for unrecoverable commit errors. + COMMIT = 2; + } + + /* + * Supported subscription replay start values. + * By default, the subscription will start at the tip of the stream if ReplayPreset is not specified. + */ + enum ReplayPreset { + // Start the subscription at the tip of the stream. + LATEST = 0; + // Start the subscription at the earliest point in the stream. + EARLIEST = 1; + // Start the subscription after a custom point in the stream. This must be set with a valid replay_id in the FetchRequest. + CUSTOM = 2; + } + + /* + * Request for the Subscribe streaming RPC method. This request is used to: + * 1. Establish the initial subscribe stream. + * 2. Request more events from the subscription stream. + * Flow Control is handled by the subscriber via num_requested. + * A client can specify a starting point for the subscription with replay_preset and replay_id combinations. + * If no replay_preset is specified, the subscription starts at LATEST (tip of the stream). + * replay_preset and replay_id values are only consumed as part of the first FetchRequest. If + * a client needs to start at another point in the stream, it must start a new subscription. + */ + message FetchRequest { + /* + * Identifies a topic for subscription in the very first FetchRequest of the stream. The topic cannot change + * in subsequent FetchRequests within the same subscribe stream, but can be omitted for efficiency. + */ + string topic_name = 1; + + /* + * Subscription starting point. This is consumed only as part of the first FetchRequest + * when the subscription is set up. + */ + ReplayPreset replay_preset = 2; + /* + * If replay_preset of CUSTOM is selected, specify the subscription point to start after. + * This is consumed only as part of the first FetchRequest when the subscription is set up. + */ + bytes replay_id = 3; + /* + * Number of events a client is ready to accept. Each subsequent FetchRequest informs the server + * of additional processing capacity available on the client side. There is no guarantee of equal number of + * FetchResponse messages to be sent back. There is not necessarily a correspondence between + * number of requested events in FetchRequest and the number of events returned in subsequent + * FetchResponses. + */ + int32 num_requested = 4; + // For internal Salesforce use only. + string auth_refresh = 5; + } + + /* + * Response for the Subscribe streaming RPC method. This returns ConsumerEvent(s). + * If there are no events to deliver, the server sends an empty batch fetch response with the latest replay ID. The + * empty fetch response is sent within 270 seconds. An empty fetch response provides a periodic keepalive from the + * server and the latest replay ID. + */ + message FetchResponse { + // Received events for subscription for client consumption + repeated ConsumerEvent events = 1; + // Latest replay ID of a subscription. Enables clients with an updated replay value so that they can keep track + // of their last consumed replay. Clients will not have to start a subscription at a very old replay in the case where a resubscribe is necessary. + bytes latest_replay_id = 2; + // RPC ID used to trace errors. + string rpc_id = 3; + // Number of remaining events to be delivered to the client for a Subscribe RPC call. + int32 pending_num_requested = 4; + } + + /* + * Request for the GetSchema RPC method. The schema request is based on the event schema ID. + */ + message SchemaRequest { + // Schema fingerprint for this event, which is a hash of the schema. + string schema_id = 1; + } + + /* + * Response for the GetSchema RPC method. This returns the schema ID and schema of an event. + */ + message SchemaInfo { + // Avro schema in JSON format + string schema_json = 1; + // Schema fingerprint + string schema_id = 2; + // RPC ID used to trace errors. + string rpc_id = 3; + } + + // Request for the Publish and PublishStream RPC method. + message PublishRequest { + // Topic to publish on + string topic_name = 1; + // Batch of ProducerEvent(s) to send + repeated ProducerEvent events = 2; + // For internal Salesforce use only. + string auth_refresh = 3; + } + + /* + * Response for the Publish and PublishStream RPC methods. This returns + * a list of PublishResults for each event that the client attempted to + * publish. PublishResult indicates if publish succeeded or not + * for each event. It also returns the schema ID that was used to create + * the ProducerEvents in the PublishRequest. + */ + message PublishResponse { + // Publish results + repeated PublishResult results = 1; + // Schema fingerprint for this event, which is a hash of the schema + string schema_id = 2; + // RPC ID used to trace errors. + string rpc_id = 3; + } + + /* + * This feature is part of an open beta release and is subject to the applicable + * Beta Services Terms provided at Agreements and Terms + * (https://www.salesforce.com/company/legal/agreements/). + * + * Request for the ManagedSubscribe streaming RPC method. This request is used to: + * 1. Establish the initial managed subscribe stream. + * 2. Request more events from the subscription stream. + * 3. Commit a Replay ID using CommitReplayRequest. + */ + message ManagedFetchRequest { + /* + * Managed subscription ID or developer name. This value corresponds to the + * ID or developer name of the ManagedEventSubscription Tooling API record. + * This value is consumed as part of the first ManagedFetchRequest only. + * The subscription_id cannot change in subsequent ManagedFetchRequests + * within the same subscribe stream, but can be omitted for efficiency. + */ + string subscription_id = 1; + string developer_name = 2; + /* + * Number of events a client is ready to accept. Each subsequent FetchRequest informs the server + * of additional processing capacity available on the client side. There is no guarantee of equal number of + * FetchResponse messages to be sent back. There is not necessarily a correspondence between + * number of requested events in FetchRequest and the number of events returned in subsequent + * FetchResponses. + */ + int32 num_requested = 3; + // For internal Salesforce use only. + string auth_refresh = 4; + CommitReplayRequest commit_replay_id_request = 5; + + } + + /* + * This feature is part of an open beta release and is subject to the applicable + * Beta Services Terms provided at Agreements and Terms + * (https://www.salesforce.com/company/legal/agreements/). + * + * Response for the ManagedSubscribe streaming RPC method. This can return + * ConsumerEvent(s) or CommitReplayResponse along with other metadata. + */ + message ManagedFetchResponse { + // Received events for subscription for client consumption + repeated ConsumerEvent events = 1; + // Latest replay ID of a subscription. + bytes latest_replay_id = 2; + // RPC ID used to trace errors. + string rpc_id = 3; + // Number of remaining events to be delivered to the client for a Subscribe RPC call. + int32 pending_num_requested = 4; + // commit response + CommitReplayResponse commit_response = 5; + } + + /* + * This feature is part of an open beta release and is subject to the applicable + * Beta Services Terms provided at Agreements and Terms + * (https://www.salesforce.com/company/legal/agreements/). + * + * Request to commit a Replay ID for the last processed event or for the latest + * replay ID received in an empty batch of events. + */ + message CommitReplayRequest { + // commit_request_id to identify commit responses + string commit_request_id = 1; + // replayId to commit + bytes replay_id = 2; + } + + /* + * This feature is part of an open beta release and is subject to the applicable + * Beta Services Terms provided at Agreements and Terms + * (https://www.salesforce.com/company/legal/agreements/). + * + * There is no guaranteed 1:1 CommitReplayRequest to CommitReplayResponse. + * N CommitReplayRequest(s) can get compressed in a batch resulting in a single + * CommitReplayResponse which reflects the latest values of last + * CommitReplayRequest in that batch. + */ + message CommitReplayResponse { + // commit_request_id to identify commit responses. + string commit_request_id = 1; + // replayId that may have been committed + bytes replay_id = 2; + // for failed commits + Error error = 3; + // time when server received request in epoch ms + int64 process_time = 4; + } + + /* + * The Pub/Sub API provides a single interface for publishing and subscribing to platform events, including real-time + * event monitoring events, and change data capture events. The Pub/Sub API is a gRPC API that is based on HTTP/2. + * + * A session token is needed to authenticate. Any of the Salesforce supported + * OAuth flows can be used to obtain a session token: + * https://help.salesforce.com/articleView?id=sf.remoteaccess_oauth_flows.htm&type=5 + * + * For each RPC, a client needs to pass authentication information + * as metadata headers (https://www.grpc.io/docs/guides/concepts/#metadata) with their method call. + * + * For Salesforce session token authentication, use: + * accesstoken : access token + * instanceurl : Salesforce instance URL + * tenantid : tenant/org id of the client + * + * StatusException is thrown in case of response failure for any request. + */ + service PubSub { + /* + * Bidirectional streaming RPC to subscribe to a Topic. The subscription is pull-based. A client can request + * for more events as it consumes events. This enables a client to handle flow control based on the client's processing speed. + * + * Typical flow: + * 1. Client requests for X number of events via FetchRequest. + * 2. Server receives request and delivers events until X events are delivered to the client via one or more FetchResponse messages. + * 3. Client consumes the FetchResponse messages as they come. + * 4. Client issues new FetchRequest for Y more number of events. This request can + * come before the server has delivered the earlier requested X number of events + * so the client gets a continuous stream of events if any. + * + * If a client requests more events before the server finishes the last + * requested amount, the server appends the new amount to the current amount of + * events it still needs to fetch and deliver. + * + * A client can subscribe at any point in the stream by providing a replay option in the first FetchRequest. + * The replay option is honored for the first FetchRequest received from a client. Any subsequent FetchRequests with a + * new replay option are ignored. A client needs to call the Subscribe RPC again to restart the subscription + * at a new point in the stream. + * + * The first FetchRequest of the stream identifies the topic to subscribe to. + * If any subsequent FetchRequest provides topic_name, it must match what + * was provided in the first FetchRequest; otherwise, the RPC returns an error + * with INVALID_ARGUMENT status. + */ + rpc Subscribe (stream FetchRequest) returns (stream FetchResponse); + + // Get the event schema for a topic based on a schema ID. + rpc GetSchema (SchemaRequest) returns (SchemaInfo); + + /* + * Get the topic Information related to the specified topic. + */ + rpc GetTopic (TopicRequest) returns (TopicInfo); + + /* + * Send a publish request to synchronously publish events to a topic. + */ + rpc Publish (PublishRequest) returns (PublishResponse); + + /* + * Bidirectional Streaming RPC to publish events to the event bus. + * PublishRequest contains the batch of events to publish. + * + * The first PublishRequest of the stream identifies the topic to publish on. + * If any subsequent PublishRequest provides topic_name, it must match what + * was provided in the first PublishRequest; otherwise, the RPC returns an error + * with INVALID_ARGUMENT status. + * + * The server returns a PublishResponse for each PublishRequest when publish is + * complete for the batch. A client does not have to wait for a PublishResponse + * before sending a new PublishRequest, i.e. multiple publish batches can be queued + * up, which allows for higher publish rate as a client can asynchronously + * publish more events while publishes are still in flight on the server side. + * + * PublishResponse holds a PublishResult for each event published that indicates success + * or failure of the publish. A client can then retry the publish as needed before sending + * more PublishRequests for new events to publish. + * + * A client must send a valid publish request with one or more events every 70 seconds to hold on to the stream. + * Otherwise, the server closes the stream and notifies the client. Once the client is notified of the stream closure, + * it must make a new PublishStream call to resume publishing. + */ + rpc PublishStream (stream PublishRequest) returns (stream PublishResponse); + + /* + * This feature is part of an open beta release and is subject to the applicable + * Beta Services Terms provided at Agreements and Terms + * (https://www.salesforce.com/company/legal/agreements/). + * + * Same as Subscribe, but for Managed Subscription clients. + * This feature is part of an open beta release. + */ + rpc ManagedSubscribe (stream ManagedFetchRequest) returns (stream ManagedFetchResponse); + } + + // Style guide: https://developers.google.com/protocol-buffers/docs/style \ No newline at end of file diff --git a/proto/eventbus/v1/pubsub_api_grpc.pb.go b/proto/eventbus/v1/pubsub_api_grpc.pb.go new file mode 100644 index 0000000..bd8681f --- /dev/null +++ b/proto/eventbus/v1/pubsub_api_grpc.pb.go @@ -0,0 +1,544 @@ +// +// Salesforce Pub/Sub API Version 1. + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.4.0 +// - protoc (unknown) +// source: eventbus/v1/pubsub_api.proto + +package eventbusv1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.62.0 or later. +const _ = grpc.SupportPackageIsVersion8 + +const ( + PubSub_Subscribe_FullMethodName = "/eventbus.v1.PubSub/Subscribe" + PubSub_GetSchema_FullMethodName = "/eventbus.v1.PubSub/GetSchema" + PubSub_GetTopic_FullMethodName = "/eventbus.v1.PubSub/GetTopic" + PubSub_Publish_FullMethodName = "/eventbus.v1.PubSub/Publish" + PubSub_PublishStream_FullMethodName = "/eventbus.v1.PubSub/PublishStream" + PubSub_ManagedSubscribe_FullMethodName = "/eventbus.v1.PubSub/ManagedSubscribe" +) + +// PubSubClient is the client API for PubSub service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// The Pub/Sub API provides a single interface for publishing and subscribing to platform events, including real-time +// event monitoring events, and change data capture events. The Pub/Sub API is a gRPC API that is based on HTTP/2. +// +// A session token is needed to authenticate. Any of the Salesforce supported +// OAuth flows can be used to obtain a session token: +// https://help.salesforce.com/articleView?id=sf.remoteaccess_oauth_flows.htm&type=5 +// +// For each RPC, a client needs to pass authentication information +// as metadata headers (https://www.grpc.io/docs/guides/concepts/#metadata) with their method call. +// +// For Salesforce session token authentication, use: +// +// accesstoken : access token +// instanceurl : Salesforce instance URL +// tenantid : tenant/org id of the client +// +// StatusException is thrown in case of response failure for any request. +type PubSubClient interface { + // Bidirectional streaming RPC to subscribe to a Topic. The subscription is pull-based. A client can request + // for more events as it consumes events. This enables a client to handle flow control based on the client's processing speed. + // + // Typical flow: + // 1. Client requests for X number of events via FetchRequest. + // 2. Server receives request and delivers events until X events are delivered to the client via one or more FetchResponse messages. + // 3. Client consumes the FetchResponse messages as they come. + // 4. Client issues new FetchRequest for Y more number of events. This request can + // come before the server has delivered the earlier requested X number of events + // so the client gets a continuous stream of events if any. + // + // If a client requests more events before the server finishes the last + // requested amount, the server appends the new amount to the current amount of + // events it still needs to fetch and deliver. + // + // A client can subscribe at any point in the stream by providing a replay option in the first FetchRequest. + // The replay option is honored for the first FetchRequest received from a client. Any subsequent FetchRequests with a + // new replay option are ignored. A client needs to call the Subscribe RPC again to restart the subscription + // at a new point in the stream. + // + // The first FetchRequest of the stream identifies the topic to subscribe to. + // If any subsequent FetchRequest provides topic_name, it must match what + // was provided in the first FetchRequest; otherwise, the RPC returns an error + // with INVALID_ARGUMENT status. + Subscribe(ctx context.Context, opts ...grpc.CallOption) (PubSub_SubscribeClient, error) + // Get the event schema for a topic based on a schema ID. + GetSchema(ctx context.Context, in *SchemaRequest, opts ...grpc.CallOption) (*SchemaInfo, error) + // Get the topic Information related to the specified topic. + GetTopic(ctx context.Context, in *TopicRequest, opts ...grpc.CallOption) (*TopicInfo, error) + // Send a publish request to synchronously publish events to a topic. + Publish(ctx context.Context, in *PublishRequest, opts ...grpc.CallOption) (*PublishResponse, error) + // Bidirectional Streaming RPC to publish events to the event bus. + // PublishRequest contains the batch of events to publish. + // + // The first PublishRequest of the stream identifies the topic to publish on. + // If any subsequent PublishRequest provides topic_name, it must match what + // was provided in the first PublishRequest; otherwise, the RPC returns an error + // with INVALID_ARGUMENT status. + // + // The server returns a PublishResponse for each PublishRequest when publish is + // complete for the batch. A client does not have to wait for a PublishResponse + // before sending a new PublishRequest, i.e. multiple publish batches can be queued + // up, which allows for higher publish rate as a client can asynchronously + // publish more events while publishes are still in flight on the server side. + // + // PublishResponse holds a PublishResult for each event published that indicates success + // or failure of the publish. A client can then retry the publish as needed before sending + // more PublishRequests for new events to publish. + // + // A client must send a valid publish request with one or more events every 70 seconds to hold on to the stream. + // Otherwise, the server closes the stream and notifies the client. Once the client is notified of the stream closure, + // it must make a new PublishStream call to resume publishing. + PublishStream(ctx context.Context, opts ...grpc.CallOption) (PubSub_PublishStreamClient, error) + // This feature is part of an open beta release and is subject to the applicable + // Beta Services Terms provided at Agreements and Terms + // (https://www.salesforce.com/company/legal/agreements/). + // + // Same as Subscribe, but for Managed Subscription clients. + // This feature is part of an open beta release. + ManagedSubscribe(ctx context.Context, opts ...grpc.CallOption) (PubSub_ManagedSubscribeClient, error) +} + +type pubSubClient struct { + cc grpc.ClientConnInterface +} + +func NewPubSubClient(cc grpc.ClientConnInterface) PubSubClient { + return &pubSubClient{cc} +} + +func (c *pubSubClient) Subscribe(ctx context.Context, opts ...grpc.CallOption) (PubSub_SubscribeClient, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &PubSub_ServiceDesc.Streams[0], PubSub_Subscribe_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &pubSubSubscribeClient{ClientStream: stream} + return x, nil +} + +type PubSub_SubscribeClient interface { + Send(*FetchRequest) error + Recv() (*FetchResponse, error) + grpc.ClientStream +} + +type pubSubSubscribeClient struct { + grpc.ClientStream +} + +func (x *pubSubSubscribeClient) Send(m *FetchRequest) error { + return x.ClientStream.SendMsg(m) +} + +func (x *pubSubSubscribeClient) Recv() (*FetchResponse, error) { + m := new(FetchResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *pubSubClient) GetSchema(ctx context.Context, in *SchemaRequest, opts ...grpc.CallOption) (*SchemaInfo, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SchemaInfo) + err := c.cc.Invoke(ctx, PubSub_GetSchema_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *pubSubClient) GetTopic(ctx context.Context, in *TopicRequest, opts ...grpc.CallOption) (*TopicInfo, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(TopicInfo) + err := c.cc.Invoke(ctx, PubSub_GetTopic_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *pubSubClient) Publish(ctx context.Context, in *PublishRequest, opts ...grpc.CallOption) (*PublishResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(PublishResponse) + err := c.cc.Invoke(ctx, PubSub_Publish_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *pubSubClient) PublishStream(ctx context.Context, opts ...grpc.CallOption) (PubSub_PublishStreamClient, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &PubSub_ServiceDesc.Streams[1], PubSub_PublishStream_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &pubSubPublishStreamClient{ClientStream: stream} + return x, nil +} + +type PubSub_PublishStreamClient interface { + Send(*PublishRequest) error + Recv() (*PublishResponse, error) + grpc.ClientStream +} + +type pubSubPublishStreamClient struct { + grpc.ClientStream +} + +func (x *pubSubPublishStreamClient) Send(m *PublishRequest) error { + return x.ClientStream.SendMsg(m) +} + +func (x *pubSubPublishStreamClient) Recv() (*PublishResponse, error) { + m := new(PublishResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *pubSubClient) ManagedSubscribe(ctx context.Context, opts ...grpc.CallOption) (PubSub_ManagedSubscribeClient, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &PubSub_ServiceDesc.Streams[2], PubSub_ManagedSubscribe_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &pubSubManagedSubscribeClient{ClientStream: stream} + return x, nil +} + +type PubSub_ManagedSubscribeClient interface { + Send(*ManagedFetchRequest) error + Recv() (*ManagedFetchResponse, error) + grpc.ClientStream +} + +type pubSubManagedSubscribeClient struct { + grpc.ClientStream +} + +func (x *pubSubManagedSubscribeClient) Send(m *ManagedFetchRequest) error { + return x.ClientStream.SendMsg(m) +} + +func (x *pubSubManagedSubscribeClient) Recv() (*ManagedFetchResponse, error) { + m := new(ManagedFetchResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// PubSubServer is the server API for PubSub service. +// All implementations must embed UnimplementedPubSubServer +// for forward compatibility +// +// The Pub/Sub API provides a single interface for publishing and subscribing to platform events, including real-time +// event monitoring events, and change data capture events. The Pub/Sub API is a gRPC API that is based on HTTP/2. +// +// A session token is needed to authenticate. Any of the Salesforce supported +// OAuth flows can be used to obtain a session token: +// https://help.salesforce.com/articleView?id=sf.remoteaccess_oauth_flows.htm&type=5 +// +// For each RPC, a client needs to pass authentication information +// as metadata headers (https://www.grpc.io/docs/guides/concepts/#metadata) with their method call. +// +// For Salesforce session token authentication, use: +// +// accesstoken : access token +// instanceurl : Salesforce instance URL +// tenantid : tenant/org id of the client +// +// StatusException is thrown in case of response failure for any request. +type PubSubServer interface { + // Bidirectional streaming RPC to subscribe to a Topic. The subscription is pull-based. A client can request + // for more events as it consumes events. This enables a client to handle flow control based on the client's processing speed. + // + // Typical flow: + // 1. Client requests for X number of events via FetchRequest. + // 2. Server receives request and delivers events until X events are delivered to the client via one or more FetchResponse messages. + // 3. Client consumes the FetchResponse messages as they come. + // 4. Client issues new FetchRequest for Y more number of events. This request can + // come before the server has delivered the earlier requested X number of events + // so the client gets a continuous stream of events if any. + // + // If a client requests more events before the server finishes the last + // requested amount, the server appends the new amount to the current amount of + // events it still needs to fetch and deliver. + // + // A client can subscribe at any point in the stream by providing a replay option in the first FetchRequest. + // The replay option is honored for the first FetchRequest received from a client. Any subsequent FetchRequests with a + // new replay option are ignored. A client needs to call the Subscribe RPC again to restart the subscription + // at a new point in the stream. + // + // The first FetchRequest of the stream identifies the topic to subscribe to. + // If any subsequent FetchRequest provides topic_name, it must match what + // was provided in the first FetchRequest; otherwise, the RPC returns an error + // with INVALID_ARGUMENT status. + Subscribe(PubSub_SubscribeServer) error + // Get the event schema for a topic based on a schema ID. + GetSchema(context.Context, *SchemaRequest) (*SchemaInfo, error) + // Get the topic Information related to the specified topic. + GetTopic(context.Context, *TopicRequest) (*TopicInfo, error) + // Send a publish request to synchronously publish events to a topic. + Publish(context.Context, *PublishRequest) (*PublishResponse, error) + // Bidirectional Streaming RPC to publish events to the event bus. + // PublishRequest contains the batch of events to publish. + // + // The first PublishRequest of the stream identifies the topic to publish on. + // If any subsequent PublishRequest provides topic_name, it must match what + // was provided in the first PublishRequest; otherwise, the RPC returns an error + // with INVALID_ARGUMENT status. + // + // The server returns a PublishResponse for each PublishRequest when publish is + // complete for the batch. A client does not have to wait for a PublishResponse + // before sending a new PublishRequest, i.e. multiple publish batches can be queued + // up, which allows for higher publish rate as a client can asynchronously + // publish more events while publishes are still in flight on the server side. + // + // PublishResponse holds a PublishResult for each event published that indicates success + // or failure of the publish. A client can then retry the publish as needed before sending + // more PublishRequests for new events to publish. + // + // A client must send a valid publish request with one or more events every 70 seconds to hold on to the stream. + // Otherwise, the server closes the stream and notifies the client. Once the client is notified of the stream closure, + // it must make a new PublishStream call to resume publishing. + PublishStream(PubSub_PublishStreamServer) error + // This feature is part of an open beta release and is subject to the applicable + // Beta Services Terms provided at Agreements and Terms + // (https://www.salesforce.com/company/legal/agreements/). + // + // Same as Subscribe, but for Managed Subscription clients. + // This feature is part of an open beta release. + ManagedSubscribe(PubSub_ManagedSubscribeServer) error + mustEmbedUnimplementedPubSubServer() +} + +// UnimplementedPubSubServer must be embedded to have forward compatible implementations. +type UnimplementedPubSubServer struct { +} + +func (UnimplementedPubSubServer) Subscribe(PubSub_SubscribeServer) error { + return status.Errorf(codes.Unimplemented, "method Subscribe not implemented") +} +func (UnimplementedPubSubServer) GetSchema(context.Context, *SchemaRequest) (*SchemaInfo, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetSchema not implemented") +} +func (UnimplementedPubSubServer) GetTopic(context.Context, *TopicRequest) (*TopicInfo, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetTopic not implemented") +} +func (UnimplementedPubSubServer) Publish(context.Context, *PublishRequest) (*PublishResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Publish not implemented") +} +func (UnimplementedPubSubServer) PublishStream(PubSub_PublishStreamServer) error { + return status.Errorf(codes.Unimplemented, "method PublishStream not implemented") +} +func (UnimplementedPubSubServer) ManagedSubscribe(PubSub_ManagedSubscribeServer) error { + return status.Errorf(codes.Unimplemented, "method ManagedSubscribe not implemented") +} +func (UnimplementedPubSubServer) mustEmbedUnimplementedPubSubServer() {} + +// UnsafePubSubServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to PubSubServer will +// result in compilation errors. +type UnsafePubSubServer interface { + mustEmbedUnimplementedPubSubServer() +} + +func RegisterPubSubServer(s grpc.ServiceRegistrar, srv PubSubServer) { + s.RegisterService(&PubSub_ServiceDesc, srv) +} + +func _PubSub_Subscribe_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(PubSubServer).Subscribe(&pubSubSubscribeServer{ServerStream: stream}) +} + +type PubSub_SubscribeServer interface { + Send(*FetchResponse) error + Recv() (*FetchRequest, error) + grpc.ServerStream +} + +type pubSubSubscribeServer struct { + grpc.ServerStream +} + +func (x *pubSubSubscribeServer) Send(m *FetchResponse) error { + return x.ServerStream.SendMsg(m) +} + +func (x *pubSubSubscribeServer) Recv() (*FetchRequest, error) { + m := new(FetchRequest) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _PubSub_GetSchema_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SchemaRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PubSubServer).GetSchema(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PubSub_GetSchema_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PubSubServer).GetSchema(ctx, req.(*SchemaRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PubSub_GetTopic_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(TopicRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PubSubServer).GetTopic(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PubSub_GetTopic_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PubSubServer).GetTopic(ctx, req.(*TopicRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PubSub_Publish_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PublishRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PubSubServer).Publish(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PubSub_Publish_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PubSubServer).Publish(ctx, req.(*PublishRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PubSub_PublishStream_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(PubSubServer).PublishStream(&pubSubPublishStreamServer{ServerStream: stream}) +} + +type PubSub_PublishStreamServer interface { + Send(*PublishResponse) error + Recv() (*PublishRequest, error) + grpc.ServerStream +} + +type pubSubPublishStreamServer struct { + grpc.ServerStream +} + +func (x *pubSubPublishStreamServer) Send(m *PublishResponse) error { + return x.ServerStream.SendMsg(m) +} + +func (x *pubSubPublishStreamServer) Recv() (*PublishRequest, error) { + m := new(PublishRequest) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _PubSub_ManagedSubscribe_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(PubSubServer).ManagedSubscribe(&pubSubManagedSubscribeServer{ServerStream: stream}) +} + +type PubSub_ManagedSubscribeServer interface { + Send(*ManagedFetchResponse) error + Recv() (*ManagedFetchRequest, error) + grpc.ServerStream +} + +type pubSubManagedSubscribeServer struct { + grpc.ServerStream +} + +func (x *pubSubManagedSubscribeServer) Send(m *ManagedFetchResponse) error { + return x.ServerStream.SendMsg(m) +} + +func (x *pubSubManagedSubscribeServer) Recv() (*ManagedFetchRequest, error) { + m := new(ManagedFetchRequest) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// PubSub_ServiceDesc is the grpc.ServiceDesc for PubSub service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var PubSub_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "eventbus.v1.PubSub", + HandlerType: (*PubSubServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetSchema", + Handler: _PubSub_GetSchema_Handler, + }, + { + MethodName: "GetTopic", + Handler: _PubSub_GetTopic_Handler, + }, + { + MethodName: "Publish", + Handler: _PubSub_Publish_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "Subscribe", + Handler: _PubSub_Subscribe_Handler, + ServerStreams: true, + ClientStreams: true, + }, + { + StreamName: "PublishStream", + Handler: _PubSub_PublishStream_Handler, + ServerStreams: true, + ClientStreams: true, + }, + { + StreamName: "ManagedSubscribe", + Handler: _PubSub_ManagedSubscribe_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "eventbus/v1/pubsub_api.proto", +} diff --git a/source/source.go b/source/source.go index 79de9ba..779207b 100644 --- a/source/source.go +++ b/source/source.go @@ -33,8 +33,10 @@ import ( const sfCometDVersion = "54.0" -var OAuthClientFactory = oauth.NewDefaultClient -var StreamingClientFactory = cometd.NewDefaultClient +var ( + OAuthClientFactory = oauth.NewDefaultClient + StreamingClientFactory = cometd.NewDefaultClient +) var ErrConnectorIsStopped = errors.New("connector is stopped") @@ -62,7 +64,8 @@ func (s *Source) Parameters() config.Parameters { Description: "Authorization service based on Organization’s Domain Name (e.g.: https://MyDomainName.my.salesforce.com -> `MyDomainName`) or `sandbox` for test environment.", Validations: []config.Validation{ config.ValidationRequired{}, - }}, + }, + }, ConfigKeyClientID: { Description: "OAuth Client ID (Consumer Key).", Validations: []config.Validation{ @@ -102,6 +105,7 @@ func (s *Source) Parameters() config.Parameters { }, } } + func (s *Source) Configure(_ context.Context, cfgRaw config.Config) (err error) { s.config, err = ParseConfig(cfgRaw) if err != nil { diff --git a/source_pubsub/client.go b/source_pubsub/client.go new file mode 100644 index 0000000..54c5f16 --- /dev/null +++ b/source_pubsub/client.go @@ -0,0 +1,706 @@ +// Copyright © 2022 Meroxa, Inc. and Miquido +// +// 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 source + +import ( + "context" + "crypto/x509" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "io" + "strings" + "sync" + "time" + + rt "github.com/avast/retry-go/v4" + eventbusv1 "github.com/conduitio-labs/conduit-connector-salesforce/proto/eventbus/v1" + "github.com/conduitio-labs/conduit-connector-salesforce/source_pubsub/position" + "github.com/conduitio/conduit-commons/opencdc" + sdk "github.com/conduitio/conduit-connector-sdk" + "github.com/linkedin/goavro/v2" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/metadata" + "gopkg.in/tomb.v2" +) + +var ( + GRPCCallTimeout = 5 * time.Second + RetryDelay = 10 * time.Second +) + +var ErrEndOfRecords = errors.New("end of records from stream") + +type PubSubClient struct { + mu sync.Mutex + + accessToken string + instanceURL string + userID string + orgID string + replayPreset eventbusv1.ReplayPreset + + oauth authenticator + + conn *grpc.ClientConn + pubSubClient eventbusv1.PubSubClient + + codecCache map[string]*goavro.Codec + unionFields map[string]map[string]struct{} + + buffer chan ConnectResponseEvent + ticker *time.Ticker + + tomb *tomb.Tomb + topicNames []string + currentPos position.Topics + maxRetries uint +} + +type Topic struct { + retryCount uint + topicName string + replayID []byte +} + +type ConnectResponseEvent struct { + Data map[string]interface{} + EventID string + ReplayID []byte + Topic string + ReceivedAt time.Time + CurrentPosition opencdc.Position +} + +// Creates a new connection to the gRPC server and returns the wrapper struct. +func NewGRPCClient(ctx context.Context, config Config, currentPos position.Topics) (*PubSubClient, error) { + sdk.Logger(ctx).Info(). + Strs("topics", config.TopicNames). + Msgf("Starting GRPC client") + + var transportCreds credentials.TransportCredentials + var replayPreset eventbusv1.ReplayPreset + + if config.InsecureSkipVerify { + transportCreds = insecure.NewCredentials() + } else { + transportCreds = credentials.NewClientTLSFromCert(getCerts(), "") + } + + dialOpts := []grpc.DialOption{ + grpc.WithTransportCredentials(transportCreds), + } + + conn, err := grpc.NewClient(config.PubsubAddress, dialOpts...) + if err != nil { + return nil, fmt.Errorf("gRPC dial: %w", err) + } + + creds, err := NewCredentials(config.ClientID, config.ClientSecret, config.OAuthEndpoint) + if err != nil { + return nil, err + } + + t, _ := tomb.WithContext(ctx) + + if config.ReplayPreset == "latest" { + replayPreset = eventbusv1.ReplayPreset_LATEST + } else { + replayPreset = eventbusv1.ReplayPreset_EARLIEST + } + + currentPos.SetTopics(config.TopicNames) + + return &PubSubClient{ + conn: conn, + pubSubClient: eventbusv1.NewPubSubClient(conn), + codecCache: make(map[string]*goavro.Codec), + unionFields: make(map[string]map[string]struct{}), + replayPreset: replayPreset, + buffer: make(chan ConnectResponseEvent), + ticker: time.NewTicker(config.PollingPeriod), + topicNames: config.TopicNames, + currentPos: currentPos, + oauth: &oauth{Credentials: creds}, + tomb: t, + maxRetries: config.RetryCount, + }, nil +} + +// Initializes the pubsub client by authenticating and. +func (c *PubSubClient) Initialize(ctx context.Context) error { + sdk.Logger(ctx).Info().Msgf("Initizalizing PubSub client") + + if err := c.login(ctx); err != nil { + return err + } + + if err := c.canSubscribe(ctx); err != nil { + return err + } + + for _, topic := range c.topicNames { + c.tomb.Go(func() error { + ctx := c.tomb.Context(nil) //nolint:staticcheck // SA1012 tomb expects nil + + return c.startCDC(ctx, Topic{ + topicName: topic, + retryCount: c.maxRetries, + replayID: c.currentPos.TopicReplayID(topic), + }) + }) + } + + go func() { + <-c.tomb.Dead() + + sdk.Logger(ctx).Info().Err(c.tomb.Err()).Msg("tomb died, closing buffer") + close(c.buffer) + }() + + return nil +} + +func (c *PubSubClient) login(ctx context.Context) error { + authResp, err := c.oauth.Login() + if err != nil { + return err + } + + userInfoResp, err := c.oauth.UserInfo(authResp.AccessToken) + if err != nil { + return err + } + + c.mu.Lock() + defer c.mu.Unlock() + + c.accessToken = authResp.AccessToken + c.instanceURL = authResp.InstanceURL + c.userID = userInfoResp.UserID + c.orgID = userInfoResp.OrganizationID + + sdk.Logger(ctx).Info(). + Str("instance_url", c.instanceURL). + Str("user_id", c.userID). + Str("org_id", c.orgID). + Strs("topics", c.topicNames). + Msg("successfully authenticated") + + return nil +} + +// Wrapper function around the GetTopic RPC. This will add the OAuth credentials and make a call to fetch data about a specific topic. +func (c *PubSubClient) canSubscribe(_ context.Context) error { + var trailer metadata.MD + + for _, topic := range c.topicNames { + req := &eventbusv1.TopicRequest{ + TopicName: topic, + } + + ctx, cancel := context.WithTimeout(c.getAuthContext(), GRPCCallTimeout) + defer cancel() + + resp, err := c.pubSubClient.GetTopic(ctx, req, grpc.Trailer(&trailer)) + if err != nil { + return fmt.Errorf("failed to retrieve topic %q: %w", topic, err) + } + + if !resp.CanSubscribe { + return fmt.Errorf("user %q not allowed to subscribe to %q", c.userID, resp.TopicName) + } + + sdk.Logger(ctx).Debug(). + Bool("can_subscribe", resp.CanSubscribe). + Str("topic", resp.TopicName). + Msgf("client allowed to subscribe to events on %q", topic) + } + + return nil +} + +// Next returns the next record from the buffer. +func (c *PubSubClient) Next(ctx context.Context) (opencdc.Record, error) { + select { + case <-ctx.Done(): + return opencdc.Record{}, fmt.Errorf("next: context done: %w", ctx.Err()) + case event, ok := <-c.buffer: + if !ok { + if err := c.tomb.Err(); err != nil { + return opencdc.Record{}, fmt.Errorf("tomb exited: %w", err) + } + return opencdc.Record{}, ErrEndOfRecords + } + return c.buildRecord(event) + } +} + +// Stop ends CDC processing. +func (c *PubSubClient) Stop(ctx context.Context) { + c.ticker.Stop() + + sdk.Logger(ctx).Debug(). + Msgf("stopping pubsub client on topics %q", strings.Join(c.topicNames, ",")) + + c.topicNames = nil +} + +func (c *PubSubClient) Wait(ctx context.Context) error { + tctx, cancel := context.WithTimeout(ctx, time.Second*5) + defer cancel() + + if c.tomb == nil { + return nil + } + + select { + case <-tctx.Done(): + return tctx.Err() + case <-c.tomb.Dead(): + return c.tomb.Err() + } +} + +func (c *PubSubClient) retryAuth(ctx context.Context, retry bool, topic Topic) (bool, Topic, error) { + var err error + sdk.Logger(ctx).Info().Msgf("retry connection on topic %s - retries remaining %d ", topic.topicName, topic.retryCount) + topic.retryCount-- + + if err = c.login(ctx); err != nil && topic.retryCount <= 0 { + return retry, topic, fmt.Errorf("failed to refresh auth: %w", err) + } else if err != nil { + sdk.Logger(ctx).Info().Msgf("received error on login for topic %s - retry - %d : %v ", topic.topicName, topic.retryCount, err) + retry = true + return retry, topic, fmt.Errorf("received error on subscribe for topic %s - retry - %d : %w", topic.topicName, topic.retryCount, err) + } + + if err := c.canSubscribe(ctx); err != nil && topic.retryCount <= 0 { + return retry, topic, fmt.Errorf("failed to subscribe to client topic %s: %w", topic.topicName, err) + } else if err != nil { + sdk.Logger(ctx).Info().Msgf("received error on subscribe for topic %s - retry - %d : %v", topic.topicName, topic.retryCount, err) + retry = true + return retry, topic, fmt.Errorf("received error on subscribe for topic %s - retry - %d : %w ", topic.topicName, topic.retryCount, err) + } + + retry = false + return retry, topic, nil +} + +func (c *PubSubClient) startCDC(ctx context.Context, topic Topic) error { + sdk.Logger(ctx).Info(). + Str("topic", topic.topicName). + Str("replayID", string(c.currentPos.TopicReplayID(topic.topicName))). + Msg("starting CDC processing..") + + var ( + retry bool + err error + lastRecvdAt = time.Now().UTC() + ) + + for { + sdk.Logger(ctx).Debug(). + Str("topic", topic.topicName). + Str("replayID", string(topic.replayID)). + Bool("retry", retry). + Uint("retry number", topic.retryCount). + Err(ctx.Err()). + Msg("cdc loop") + + if retry && ctx.Err() == nil { + err := rt.Do(func() error { + retry, topic, err = c.retryAuth(ctx, retry, topic) + return err + }, + rt.Delay(RetryDelay), + rt.Attempts(topic.retryCount), + ) + if err != nil { + return fmt.Errorf("error retrying (number of retries %d) for topic %s auth - %s", topic.retryCount, topic.topicName, err) + } + // once we are done with retries, reset the count + topic.retryCount = c.maxRetries + } + + select { + case <-ctx.Done(): + return ctx.Err() + case <-c.ticker.C: // detect changes every polling period. + + sdk.Logger(ctx).Debug(). + Dur("elapsed", time.Since(lastRecvdAt)). + Str("topic", topic.topicName). + Str("replayID", base64.StdEncoding.EncodeToString(topic.replayID)). + Msg("attempting to receive new events") + + lastRecvdAt = time.Now().UTC() + + events, err := c.Recv(ctx, topic.topicName, topic.replayID) + if err != nil { + sdk.Logger(ctx).Error().Err(err). + Str("topic", topic.topicName). + Str("replayID", string(topic.replayID)). + Msgf("received error on event receive: %v", err) + + if topic.retryCount > 0 { + if c.invalidReplayIDErr(err) { + sdk.Logger(ctx).Error().Err(err). + Str("topic", topic.topicName). + Str("replayID", string(topic.replayID)). + Msgf("replay id %s is invalid, retrying from preset", string(topic.replayID)) + topic.replayID = nil + } + retry = true + break + } + + return fmt.Errorf("error recv events: %w", err) + } + + sdk.Logger(ctx).Debug(). + Int("events", len(events)). + Dur("elapsed", time.Since(lastRecvdAt)). + Str("topic", topic.topicName). + Msg("received events") + + for _, e := range events { + topic.replayID = e.ReplayID + c.buffer <- e + sdk.Logger(ctx).Debug(). + Int("events", len(events)). + Dur("elapsed", time.Since(lastRecvdAt)). + Str("topic", e.Topic). + Str("replayID", base64.StdEncoding.EncodeToString(e.ReplayID)). + Msg("record sent to buffer") + } + } + } +} + +func (*PubSubClient) invalidReplayIDErr(err error) bool { + return strings.Contains(strings.ToLower(err.Error()), "replay id validation failed") +} + +func (*PubSubClient) connErr(err error) bool { + msg := err.Error() + + return strings.Contains(msg, "is unavailable") +} + +func (c *PubSubClient) buildRecord(event ConnectResponseEvent) (opencdc.Record, error) { + // TODO - ADD something here to distinguish creates, deletes, updates. + err := c.currentPos.SetTopicReplayID(event.Topic, event.ReplayID) + if err != nil { + return opencdc.Record{}, fmt.Errorf("err setting replay id %s on an event for topic %s : %w", event.ReplayID, event.Topic, err) + } + + sdk.Logger(context.Background()).Debug(). + Dur("elapsed", time.Since(event.ReceivedAt)). + Str("topic", event.Topic). + Str("replayID", base64.StdEncoding.EncodeToString(event.ReplayID)). + Str("replayID uncoded", string(event.ReplayID)). + Msg("built record, sending it as next") + + return sdk.Util.Source.NewRecordCreate( + c.currentPos.ToSDKPosition(), + opencdc.Metadata{ + "opencdc.collection": event.Topic, + }, + opencdc.StructuredData{ + "replayId": event.ReplayID, + "id": event.EventID, + }, + opencdc.StructuredData(event.Data), + ), nil +} + +// Closes the underlying connection to the gRPC server. +func (c *PubSubClient) Close(ctx context.Context) error { + if c.conn != nil { + sdk.Logger(ctx).Debug().Msg("closing pubsub gRPC connection") + + return c.conn.Close() + } + + sdk.Logger(ctx).Debug().Msg("no-op, pubsub connection is not open") + + return nil +} + +// Wrapper function around the GetSchema RPC. This will add the OAuth credentials and make a call to fetch data about a specific schema. +func (c *PubSubClient) GetSchema(schemaID string) (*eventbusv1.SchemaInfo, error) { + var trailer metadata.MD + + req := &eventbusv1.SchemaRequest{ + SchemaId: schemaID, + } + + ctx, cancel := context.WithTimeout(c.getAuthContext(), GRPCCallTimeout) + defer cancel() + + resp, err := c.pubSubClient.GetSchema(ctx, req, grpc.Trailer(&trailer)) + if err != nil { + return nil, fmt.Errorf("error getting schema from salesforce api - %s", err) + } + + return resp, nil +} + +// Wrapper function around the Subscribe RPC. This will add the OAuth credentials and create a separate streaming client that will be used to, +// fetch data from the topic. This method will continuously consume messages unless an error occurs; if an error does occur then this method will, +// return the last successfully consumed replayID as well as the error message. If no messages were successfully consumed then this method will return, +// the same replayID that it originally received as a parameter. +func (c *PubSubClient) Subscribe( + ctx context.Context, + replayPreset eventbusv1.ReplayPreset, + replayID []byte, + topic string, +) (eventbusv1.PubSub_SubscribeClient, error) { + start := time.Now().UTC() + + subscribeClient, err := c.pubSubClient.Subscribe(c.getAuthContext()) + if err != nil { + sdk.Logger(ctx).Error().Err(err). + Str("topic", topic). + Str("replayID", string(replayID)). + Msg("failed to subscribe to topic") + return nil, fmt.Errorf("failed to subscribe to topic %q: %w", topic, err) + } + + sdk.Logger(ctx).Debug(). + Str("replay_id", base64.StdEncoding.EncodeToString(replayID)). + Str("replay_preset", eventbusv1.ReplayPreset_name[int32(replayPreset)]). + Str("topic_name", topic). + Dur("elapsed", time.Since(start)). + Msgf("subscribed to %q", topic) + + initialFetchRequest := &eventbusv1.FetchRequest{ + TopicName: topic, + ReplayPreset: replayPreset, + NumRequested: 1, + } + + if replayPreset == eventbusv1.ReplayPreset_CUSTOM && len(replayID) > 0 { + initialFetchRequest.ReplayId = replayID + } + + if err := subscribeClient.Send(initialFetchRequest); err != nil { + if errors.Is(err, io.EOF) { + return nil, fmt.Errorf("received EOF on initial fetch: %w", err) + } + + return nil, fmt.Errorf("initial fetch request failed: %w", err) + } + + sdk.Logger(ctx).Debug(). + Str("replay_id", base64.StdEncoding.EncodeToString(replayID)). + Str("replay_preset", eventbusv1.ReplayPreset_name[int32(replayPreset)]). + Str("topic_name", topic). + Dur("elapsed", time.Since(start)). + Msg("first request sent") + + return subscribeClient, nil +} + +func (c *PubSubClient) Recv(ctx context.Context, topic string, replayID []byte) ([]ConnectResponseEvent, error) { + var ( + preset = c.replayPreset + start = time.Now().UTC() + ) + + if len(replayID) > 0 { + preset = eventbusv1.ReplayPreset_CUSTOM + } + + sdk.Logger(ctx).Info(). + Str("preset", preset.String()). + Str("replay_id", base64.StdEncoding.EncodeToString(replayID)). + Str("topic", topic). + Msg("preparing to subscribe") + + subClient, err := c.Subscribe(ctx, preset, replayID, topic) + if err != nil { + return nil, fmt.Errorf("error subscribing to topic on custom replay id %q: %w", + base64.StdEncoding.EncodeToString(replayID), + err, + ) + } + + sdk.Logger(ctx).Info(). + Str("preset", preset.String()). + Str("replay_id", base64.StdEncoding.EncodeToString(replayID)). + Str("topic", topic). + Dur("elapsed", time.Since(start)). + Msg("preparing to receive events") + + resp, err := subClient.Recv() + if err != nil { + if errors.Is(err, io.EOF) { + return nil, fmt.Errorf("pubsub: stream closed when receiving events: %w", err) + } + if c.connErr(err) { + sdk.Logger(ctx).Warn(). + Str("preset", preset.String()). + Str("replay_id", base64.StdEncoding.EncodeToString(replayID)). + Str("topic", topic). + Dur("elapsed", time.Since(start)). + Err(err). + Msg("error while receiving events - retrying to connect") + return nil, nil + } + return nil, err + } + + sdk.Logger(ctx).Info(). + Str("preset", preset.String()). + Str("replay_id", base64.StdEncoding.EncodeToString(replayID)). + Str("topic", topic). + Int("events", len(resp.Events)). + Dur("elapsed", time.Since(start)). + Msg("subscriber received events") + + var events []ConnectResponseEvent + + for _, e := range resp.Events { + codec, err := c.fetchCodec(ctx, e.Event.SchemaId) + if err != nil { + return events, err + } + + parsed, _, err := codec.NativeFromBinary(e.Event.Payload) + if err != nil { + return events, err + } + + payload, ok := parsed.(map[string]interface{}) + if !ok { + return events, fmt.Errorf("invalid payload type %T", payload) + } + + events = append(events, ConnectResponseEvent{ + ReplayID: e.ReplayId, + EventID: e.Event.Id, + Data: flattenUnionFields(ctx, payload, c.unionFields[e.Event.SchemaId]), + Topic: topic, + ReceivedAt: time.Now(), + }) + } + + return events, nil +} + +// Unexported helper function to retrieve the cached codec from the PubSubClient's schema cache. If the schema ID is not found in the cache, +// then a GetSchema call is made and the corresponding codec is cached for future use. +func (c *PubSubClient) fetchCodec(ctx context.Context, schemaID string) (*goavro.Codec, error) { + codec, ok := c.codecCache[schemaID] + if ok { + sdk.Logger(ctx).Trace().Msg("Fetched cached codec...") + return codec, nil + } + + sdk.Logger(ctx).Trace().Msg("Making GetSchema request for uncached schema...") + schema, err := c.GetSchema(schemaID) + if err != nil { + return nil, fmt.Errorf("error making getschema request for uncached schema - %s", err) + } + + sdk.Logger(ctx).Trace().Msg("Creating codec from uncached schema...") + schemaJSON := schema.GetSchemaJson() + codec, err = goavro.NewCodec(schemaJSON) + if err != nil { + return nil, fmt.Errorf("error creating codec from uncached schema - %s", err) + } + + c.codecCache[schemaID] = codec + + unionFields, err := parseUnionFields(ctx, schemaJSON) + if err != nil { + return nil, fmt.Errorf("error parsing union fields from schema: %w", err) + } + + c.unionFields[schemaID] = unionFields + + return codec, nil +} + +const ( + tokenHeader = "accesstoken" + instanceHeader = "instanceurl" + tenantHeader = "tenantid" +) + +// Returns a new context with the necessary authentication parameters for the gRPC server. +func (c *PubSubClient) getAuthContext() context.Context { + pairs := metadata.Pairs( + tokenHeader, c.accessToken, + instanceHeader, c.instanceURL, + tenantHeader, c.orgID, + ) + + return metadata.NewOutgoingContext(context.Background(), pairs) +} + +// Fetches system certs and returns them if possible. If unable to fetch system certs then an empty cert pool is returned instead. +func getCerts() *x509.CertPool { + if certs, err := x509.SystemCertPool(); err == nil { + return certs + } + + return x509.NewCertPool() +} + +// parseUnionFields parses the schema JSON to identify avro union fields. +func parseUnionFields(_ context.Context, schemaJSON string) (map[string]struct{}, error) { + var schema map[string]interface{} + if err := json.Unmarshal([]byte(schemaJSON), &schema); err != nil { + return nil, fmt.Errorf("failed to parse schema: %w", err) + } + + unionFields := make(map[string]struct{}) + fields := schema["fields"].([]interface{}) + for _, field := range fields { + f := field.(map[string]interface{}) + fieldType := f["type"] + if types, ok := fieldType.([]interface{}); ok && len(types) > 1 { + unionFields[f["name"].(string)] = struct{}{} + } + } + return unionFields, nil +} + +// flattenUnionFields flattens union fields decoded from Avro. +func flattenUnionFields(_ context.Context, data map[string]interface{}, unionFields map[string]struct{}) map[string]interface{} { + flatData := make(map[string]interface{}) + for key, value := range data { + if _, ok := unionFields[key]; ok { // Check if this field is a union + if valueMap, ok := value.(map[string]interface{}); ok && len(valueMap) == 1 { + for _, actualValue := range valueMap { + flatData[key] = actualValue + break + } + } else { + flatData[key] = value + } + } else { + flatData[key] = value + } + } + + return flatData +} diff --git a/source_pubsub/client_test.go b/source_pubsub/client_test.go new file mode 100644 index 0000000..6eb5709 --- /dev/null +++ b/source_pubsub/client_test.go @@ -0,0 +1,74 @@ +// Copyright © 2022 Meroxa, Inc. and Miquido +// +// 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 source + +import ( + "context" + "testing" + "time" + + eventbusv1 "github.com/conduitio-labs/conduit-connector-salesforce/proto/eventbus/v1" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "gopkg.in/tomb.v2" +) + +func TestPubSubClient_Initialize(t *testing.T) { + mockAuth := newMockAuthenticator(t) + ctx, cancel := context.WithCancel(context.Background()) + + mockAuth.EXPECT(). + Login(). + Return(&LoginResponse{AccessToken: "token", InstanceURL: "instance-url"}, nil) + + mockAuth.EXPECT(). + UserInfo("token"). + Return( + &UserInfoResponse{UserID: "my-user-id", OrganizationID: "org-id"}, + nil, + ) + + mockPubSubClient := newMockPubSubClient(t) + + mockPubSubClient.EXPECT().GetTopic( + mock.Anything, + &eventbusv1.TopicRequest{TopicName: "my-topic"}, + mock.Anything, + ).Return( + &eventbusv1.TopicInfo{TopicName: "my-topic", CanSubscribe: true}, + nil, + ) + + tt, _ := tomb.WithContext(ctx) + + c := &PubSubClient{ + oauth: mockAuth, + pubSubClient: mockPubSubClient, + tomb: tt, + buffer: make(chan ConnectResponseEvent), + topicNames: []string{"my-topic"}, + ticker: time.NewTicker(time.Second * 1), + } + + require.NoError(t, c.Initialize(ctx)) + require.True(t, c.tomb.Alive()) + + c.Stop(ctx) + cancel() + err := c.Wait(context.Background()) + require.Error(t, err) + require.ErrorIs(t, err, context.Canceled) + require.ErrorIs(t, c.tomb.Wait(), context.Canceled) +} diff --git a/source_pubsub/config.go b/source_pubsub/config.go new file mode 100644 index 0000000..1935702 --- /dev/null +++ b/source_pubsub/config.go @@ -0,0 +1,119 @@ +// Copyright © 2024 Meroxa, Inc. +// +// 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 source + +import ( + "context" + "errors" + "fmt" + "net" + "net/url" + "slices" + "time" + + sdk "github.com/conduitio/conduit-connector-sdk" +) + +//go:generate paramgen -output=paramgen_config.go Config +type Config struct { + // ClientID is the client id from the salesforce app + ClientID string `json:"clientID" validate:"required"` + + // ClientSecret is the client secret from the salesforce app + ClientSecret string `json:"clientSecret" validate:"required"` + + // OAuthEndpoint is the OAuthEndpoint from the salesforce app + OAuthEndpoint string `json:"oauthEndpoint" validate:"required"` + + // TopicName {WARN will be deprecated soon} the TopicName the source connector will subscribe to + TopicName string `json:"topicName"` + + // TopicNames are the TopicNames the source connector will subscribe to + TopicNames []string `json:"topicNames" validate:"required"` + + // Deprecated: Username is the client secret from the salesforce app. + Username string `json:"username"` + + // PollingPeriod is the client event polling interval + PollingPeriod time.Duration `json:"pollingPeriod" default:"100ms"` + + // gRPC Pubsub Salesforce API address + PubsubAddress string `json:"pubsubAddress" default:"api.pubsub.salesforce.com:7443"` + + // InsecureSkipVerify disables certificate validation + InsecureSkipVerify bool `json:"insecureSkipVerify" default:"false"` + + // Replay preset for the position the connector is fetching events from, can be latest or default to earliest. + ReplayPreset string `json:"replayPreset" default:"earliest"` + + // Number of retries allowed per read before the connector errors out + RetryCount uint `json:"retryCount" default:"10"` +} + +func (c Config) Validate(ctx context.Context) (Config, error) { + var errs []error + + // Warn about deprecated fields + if c.Username != "" { + sdk.Logger(ctx).Warn(). + Msg(`"username" is deprecated, use "clientID" and "clientSecret"`) + } + + if c.TopicName != "" { + sdk.Logger(ctx).Warn(). + Msg(`"topicName" is deprecated, use "topicNames" instead.`) + + c.TopicNames = slices.Compact(append(c.TopicNames, c.TopicName)) + } + + // Validate provided fields + if c.ClientID == "" { + errs = append(errs, fmt.Errorf("invalid client id %q", c.ClientID)) + } + + if c.ClientSecret == "" { + errs = append(errs, fmt.Errorf("invalid client secret %q", c.ClientSecret)) + } + + if c.OAuthEndpoint == "" { + errs = append(errs, fmt.Errorf("invalid oauth endpoint %q", c.OAuthEndpoint)) + } + + if len(c.TopicNames) == 0 { + errs = append(errs, fmt.Errorf("invalid TopicName name %q", c.TopicNames)) + } + + if c.PollingPeriod == 0 { + errs = append(errs, fmt.Errorf("polling period cannot be zero %d", c.PollingPeriod)) + } + + if c.PubsubAddress == "" { + errs = append(errs, fmt.Errorf("invalid pubsub address %q", c.OAuthEndpoint)) + } + + if len(errs) != 0 { + return c, errors.Join(errs...) + } + + if _, err := url.Parse(c.OAuthEndpoint); err != nil { + return c, fmt.Errorf("failed to parse oauth endpoint url: %w", err) + } + + if _, _, err := net.SplitHostPort(c.PubsubAddress); err != nil { + return c, fmt.Errorf("failed to parse pubsub address: %w", err) + } + + return c, nil +} diff --git a/source_pubsub/mock_authenticator_test.go b/source_pubsub/mock_authenticator_test.go new file mode 100644 index 0000000..0ea1d42 --- /dev/null +++ b/source_pubsub/mock_authenticator_test.go @@ -0,0 +1,147 @@ +// Code generated by mockery. DO NOT EDIT. + +package source + +import mock "github.com/stretchr/testify/mock" + +// mockAuthenticator is an autogenerated mock type for the authenticator type +type mockAuthenticator struct { + mock.Mock +} + +type mockAuthenticator_Expecter struct { + mock *mock.Mock +} + +func (_m *mockAuthenticator) EXPECT() *mockAuthenticator_Expecter { + return &mockAuthenticator_Expecter{mock: &_m.Mock} +} + +// Login provides a mock function with given fields: +func (_m *mockAuthenticator) Login() (*LoginResponse, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Login") + } + + var r0 *LoginResponse + var r1 error + if rf, ok := ret.Get(0).(func() (*LoginResponse, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() *LoginResponse); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*LoginResponse) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// mockAuthenticator_Login_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Login' +type mockAuthenticator_Login_Call struct { + *mock.Call +} + +// Login is a helper method to define mock.On call +func (_e *mockAuthenticator_Expecter) Login() *mockAuthenticator_Login_Call { + return &mockAuthenticator_Login_Call{Call: _e.mock.On("Login")} +} + +func (_c *mockAuthenticator_Login_Call) Run(run func()) *mockAuthenticator_Login_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *mockAuthenticator_Login_Call) Return(_a0 *LoginResponse, _a1 error) *mockAuthenticator_Login_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *mockAuthenticator_Login_Call) RunAndReturn(run func() (*LoginResponse, error)) *mockAuthenticator_Login_Call { + _c.Call.Return(run) + return _c +} + +// UserInfo provides a mock function with given fields: _a0 +func (_m *mockAuthenticator) UserInfo(_a0 string) (*UserInfoResponse, error) { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for UserInfo") + } + + var r0 *UserInfoResponse + var r1 error + if rf, ok := ret.Get(0).(func(string) (*UserInfoResponse, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(string) *UserInfoResponse); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*UserInfoResponse) + } + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// mockAuthenticator_UserInfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UserInfo' +type mockAuthenticator_UserInfo_Call struct { + *mock.Call +} + +// UserInfo is a helper method to define mock.On call +// - _a0 string +func (_e *mockAuthenticator_Expecter) UserInfo(_a0 interface{}) *mockAuthenticator_UserInfo_Call { + return &mockAuthenticator_UserInfo_Call{Call: _e.mock.On("UserInfo", _a0)} +} + +func (_c *mockAuthenticator_UserInfo_Call) Run(run func(_a0 string)) *mockAuthenticator_UserInfo_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *mockAuthenticator_UserInfo_Call) Return(_a0 *UserInfoResponse, _a1 error) *mockAuthenticator_UserInfo_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *mockAuthenticator_UserInfo_Call) RunAndReturn(run func(string) (*UserInfoResponse, error)) *mockAuthenticator_UserInfo_Call { + _c.Call.Return(run) + return _c +} + +// newMockAuthenticator creates a new instance of mockAuthenticator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func newMockAuthenticator(t interface { + mock.TestingT + Cleanup(func()) +}) *mockAuthenticator { + mock := &mockAuthenticator{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/source_pubsub/mock_client_test.go b/source_pubsub/mock_client_test.go new file mode 100644 index 0000000..f8758c3 --- /dev/null +++ b/source_pubsub/mock_client_test.go @@ -0,0 +1,264 @@ +// Code generated by mockery. DO NOT EDIT. + +package source + +import ( + context "context" + + opencdc "github.com/conduitio/conduit-commons/opencdc" + mock "github.com/stretchr/testify/mock" +) + +// mockClient is an autogenerated mock type for the client type +type mockClient struct { + mock.Mock +} + +type mockClient_Expecter struct { + mock *mock.Mock +} + +func (_m *mockClient) EXPECT() *mockClient_Expecter { + return &mockClient_Expecter{mock: &_m.Mock} +} + +// Close provides a mock function with given fields: _a0 +func (_m *mockClient) Close(_a0 context.Context) error { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for Close") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockClient_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' +type mockClient_Close_Call struct { + *mock.Call +} + +// Close is a helper method to define mock.On call +// - _a0 context.Context +func (_e *mockClient_Expecter) Close(_a0 interface{}) *mockClient_Close_Call { + return &mockClient_Close_Call{Call: _e.mock.On("Close", _a0)} +} + +func (_c *mockClient_Close_Call) Run(run func(_a0 context.Context)) *mockClient_Close_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *mockClient_Close_Call) Return(_a0 error) *mockClient_Close_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockClient_Close_Call) RunAndReturn(run func(context.Context) error) *mockClient_Close_Call { + _c.Call.Return(run) + return _c +} + +// Initialize provides a mock function with given fields: _a0 +func (_m *mockClient) Initialize(_a0 context.Context) error { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for Initialize") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockClient_Initialize_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Initialize' +type mockClient_Initialize_Call struct { + *mock.Call +} + +// Initialize is a helper method to define mock.On call +// - _a0 context.Context +func (_e *mockClient_Expecter) Initialize(_a0 interface{}) *mockClient_Initialize_Call { + return &mockClient_Initialize_Call{Call: _e.mock.On("Initialize", _a0)} +} + +func (_c *mockClient_Initialize_Call) Run(run func(_a0 context.Context)) *mockClient_Initialize_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *mockClient_Initialize_Call) Return(_a0 error) *mockClient_Initialize_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockClient_Initialize_Call) RunAndReturn(run func(context.Context) error) *mockClient_Initialize_Call { + _c.Call.Return(run) + return _c +} + +// Next provides a mock function with given fields: _a0 +func (_m *mockClient) Next(_a0 context.Context) (opencdc.Record, error) { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for Next") + } + + var r0 opencdc.Record + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (opencdc.Record, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(context.Context) opencdc.Record); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(opencdc.Record) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// mockClient_Next_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Next' +type mockClient_Next_Call struct { + *mock.Call +} + +// Next is a helper method to define mock.On call +// - _a0 context.Context +func (_e *mockClient_Expecter) Next(_a0 interface{}) *mockClient_Next_Call { + return &mockClient_Next_Call{Call: _e.mock.On("Next", _a0)} +} + +func (_c *mockClient_Next_Call) Run(run func(_a0 context.Context)) *mockClient_Next_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *mockClient_Next_Call) Return(_a0 opencdc.Record, _a1 error) *mockClient_Next_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *mockClient_Next_Call) RunAndReturn(run func(context.Context) (opencdc.Record, error)) *mockClient_Next_Call { + _c.Call.Return(run) + return _c +} + +// Stop provides a mock function with given fields: _a0 +func (_m *mockClient) Stop(_a0 context.Context) { + _m.Called(_a0) +} + +// mockClient_Stop_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Stop' +type mockClient_Stop_Call struct { + *mock.Call +} + +// Stop is a helper method to define mock.On call +// - _a0 context.Context +func (_e *mockClient_Expecter) Stop(_a0 interface{}) *mockClient_Stop_Call { + return &mockClient_Stop_Call{Call: _e.mock.On("Stop", _a0)} +} + +func (_c *mockClient_Stop_Call) Run(run func(_a0 context.Context)) *mockClient_Stop_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *mockClient_Stop_Call) Return() *mockClient_Stop_Call { + _c.Call.Return() + return _c +} + +func (_c *mockClient_Stop_Call) RunAndReturn(run func(context.Context)) *mockClient_Stop_Call { + _c.Call.Return(run) + return _c +} + +// Wait provides a mock function with given fields: _a0 +func (_m *mockClient) Wait(_a0 context.Context) error { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for Wait") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockClient_Wait_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Wait' +type mockClient_Wait_Call struct { + *mock.Call +} + +// Wait is a helper method to define mock.On call +// - _a0 context.Context +func (_e *mockClient_Expecter) Wait(_a0 interface{}) *mockClient_Wait_Call { + return &mockClient_Wait_Call{Call: _e.mock.On("Wait", _a0)} +} + +func (_c *mockClient_Wait_Call) Run(run func(_a0 context.Context)) *mockClient_Wait_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *mockClient_Wait_Call) Return(_a0 error) *mockClient_Wait_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockClient_Wait_Call) RunAndReturn(run func(context.Context) error) *mockClient_Wait_Call { + _c.Call.Return(run) + return _c +} + +// newMockClient creates a new instance of mockClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func newMockClient(t interface { + mock.TestingT + Cleanup(func()) +}) *mockClient { + mock := &mockClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/source_pubsub/mock_pub_sub_client_test.go b/source_pubsub/mock_pub_sub_client_test.go new file mode 100644 index 0000000..c0f1057 --- /dev/null +++ b/source_pubsub/mock_pub_sub_client_test.go @@ -0,0 +1,480 @@ +// Code generated by mockery. DO NOT EDIT. + +package source + +import ( + context "context" + + eventbusv1 "github.com/conduitio-labs/conduit-connector-salesforce/proto/eventbus/v1" + grpc "google.golang.org/grpc" + + mock "github.com/stretchr/testify/mock" +) + +// mockPubSubClient is an autogenerated mock type for the PubSubClient type +type mockPubSubClient struct { + mock.Mock +} + +type mockPubSubClient_Expecter struct { + mock *mock.Mock +} + +func (_m *mockPubSubClient) EXPECT() *mockPubSubClient_Expecter { + return &mockPubSubClient_Expecter{mock: &_m.Mock} +} + +// GetSchema provides a mock function with given fields: ctx, in, opts +func (_m *mockPubSubClient) GetSchema(ctx context.Context, in *eventbusv1.SchemaRequest, opts ...grpc.CallOption) (*eventbusv1.SchemaInfo, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetSchema") + } + + var r0 *eventbusv1.SchemaInfo + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *eventbusv1.SchemaRequest, ...grpc.CallOption) (*eventbusv1.SchemaInfo, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *eventbusv1.SchemaRequest, ...grpc.CallOption) *eventbusv1.SchemaInfo); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*eventbusv1.SchemaInfo) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *eventbusv1.SchemaRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// mockPubSubClient_GetSchema_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSchema' +type mockPubSubClient_GetSchema_Call struct { + *mock.Call +} + +// GetSchema is a helper method to define mock.On call +// - ctx context.Context +// - in *eventbusv1.SchemaRequest +// - opts ...grpc.CallOption +func (_e *mockPubSubClient_Expecter) GetSchema(ctx interface{}, in interface{}, opts ...interface{}) *mockPubSubClient_GetSchema_Call { + return &mockPubSubClient_GetSchema_Call{Call: _e.mock.On("GetSchema", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *mockPubSubClient_GetSchema_Call) Run(run func(ctx context.Context, in *eventbusv1.SchemaRequest, opts ...grpc.CallOption)) *mockPubSubClient_GetSchema_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*eventbusv1.SchemaRequest), variadicArgs...) + }) + return _c +} + +func (_c *mockPubSubClient_GetSchema_Call) Return(_a0 *eventbusv1.SchemaInfo, _a1 error) *mockPubSubClient_GetSchema_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *mockPubSubClient_GetSchema_Call) RunAndReturn(run func(context.Context, *eventbusv1.SchemaRequest, ...grpc.CallOption) (*eventbusv1.SchemaInfo, error)) *mockPubSubClient_GetSchema_Call { + _c.Call.Return(run) + return _c +} + +// GetTopic provides a mock function with given fields: ctx, in, opts +func (_m *mockPubSubClient) GetTopic(ctx context.Context, in *eventbusv1.TopicRequest, opts ...grpc.CallOption) (*eventbusv1.TopicInfo, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetTopic") + } + + var r0 *eventbusv1.TopicInfo + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *eventbusv1.TopicRequest, ...grpc.CallOption) (*eventbusv1.TopicInfo, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *eventbusv1.TopicRequest, ...grpc.CallOption) *eventbusv1.TopicInfo); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*eventbusv1.TopicInfo) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *eventbusv1.TopicRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// mockPubSubClient_GetTopic_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTopic' +type mockPubSubClient_GetTopic_Call struct { + *mock.Call +} + +// GetTopic is a helper method to define mock.On call +// - ctx context.Context +// - in *eventbusv1.TopicRequest +// - opts ...grpc.CallOption +func (_e *mockPubSubClient_Expecter) GetTopic(ctx interface{}, in interface{}, opts ...interface{}) *mockPubSubClient_GetTopic_Call { + return &mockPubSubClient_GetTopic_Call{Call: _e.mock.On("GetTopic", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *mockPubSubClient_GetTopic_Call) Run(run func(ctx context.Context, in *eventbusv1.TopicRequest, opts ...grpc.CallOption)) *mockPubSubClient_GetTopic_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*eventbusv1.TopicRequest), variadicArgs...) + }) + return _c +} + +func (_c *mockPubSubClient_GetTopic_Call) Return(_a0 *eventbusv1.TopicInfo, _a1 error) *mockPubSubClient_GetTopic_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *mockPubSubClient_GetTopic_Call) RunAndReturn(run func(context.Context, *eventbusv1.TopicRequest, ...grpc.CallOption) (*eventbusv1.TopicInfo, error)) *mockPubSubClient_GetTopic_Call { + _c.Call.Return(run) + return _c +} + +// ManagedSubscribe provides a mock function with given fields: ctx, opts +func (_m *mockPubSubClient) ManagedSubscribe(ctx context.Context, opts ...grpc.CallOption) (eventbusv1.PubSub_ManagedSubscribeClient, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ManagedSubscribe") + } + + var r0 eventbusv1.PubSub_ManagedSubscribeClient + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) (eventbusv1.PubSub_ManagedSubscribeClient, error)); ok { + return rf(ctx, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) eventbusv1.PubSub_ManagedSubscribeClient); ok { + r0 = rf(ctx, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(eventbusv1.PubSub_ManagedSubscribeClient) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ...grpc.CallOption) error); ok { + r1 = rf(ctx, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// mockPubSubClient_ManagedSubscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ManagedSubscribe' +type mockPubSubClient_ManagedSubscribe_Call struct { + *mock.Call +} + +// ManagedSubscribe is a helper method to define mock.On call +// - ctx context.Context +// - opts ...grpc.CallOption +func (_e *mockPubSubClient_Expecter) ManagedSubscribe(ctx interface{}, opts ...interface{}) *mockPubSubClient_ManagedSubscribe_Call { + return &mockPubSubClient_ManagedSubscribe_Call{Call: _e.mock.On("ManagedSubscribe", + append([]interface{}{ctx}, opts...)...)} +} + +func (_c *mockPubSubClient_ManagedSubscribe_Call) Run(run func(ctx context.Context, opts ...grpc.CallOption)) *mockPubSubClient_ManagedSubscribe_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-1) + for i, a := range args[1:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), variadicArgs...) + }) + return _c +} + +func (_c *mockPubSubClient_ManagedSubscribe_Call) Return(_a0 eventbusv1.PubSub_ManagedSubscribeClient, _a1 error) *mockPubSubClient_ManagedSubscribe_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *mockPubSubClient_ManagedSubscribe_Call) RunAndReturn(run func(context.Context, ...grpc.CallOption) (eventbusv1.PubSub_ManagedSubscribeClient, error)) *mockPubSubClient_ManagedSubscribe_Call { + _c.Call.Return(run) + return _c +} + +// Publish provides a mock function with given fields: ctx, in, opts +func (_m *mockPubSubClient) Publish(ctx context.Context, in *eventbusv1.PublishRequest, opts ...grpc.CallOption) (*eventbusv1.PublishResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Publish") + } + + var r0 *eventbusv1.PublishResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *eventbusv1.PublishRequest, ...grpc.CallOption) (*eventbusv1.PublishResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *eventbusv1.PublishRequest, ...grpc.CallOption) *eventbusv1.PublishResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*eventbusv1.PublishResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *eventbusv1.PublishRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// mockPubSubClient_Publish_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Publish' +type mockPubSubClient_Publish_Call struct { + *mock.Call +} + +// Publish is a helper method to define mock.On call +// - ctx context.Context +// - in *eventbusv1.PublishRequest +// - opts ...grpc.CallOption +func (_e *mockPubSubClient_Expecter) Publish(ctx interface{}, in interface{}, opts ...interface{}) *mockPubSubClient_Publish_Call { + return &mockPubSubClient_Publish_Call{Call: _e.mock.On("Publish", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *mockPubSubClient_Publish_Call) Run(run func(ctx context.Context, in *eventbusv1.PublishRequest, opts ...grpc.CallOption)) *mockPubSubClient_Publish_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*eventbusv1.PublishRequest), variadicArgs...) + }) + return _c +} + +func (_c *mockPubSubClient_Publish_Call) Return(_a0 *eventbusv1.PublishResponse, _a1 error) *mockPubSubClient_Publish_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *mockPubSubClient_Publish_Call) RunAndReturn(run func(context.Context, *eventbusv1.PublishRequest, ...grpc.CallOption) (*eventbusv1.PublishResponse, error)) *mockPubSubClient_Publish_Call { + _c.Call.Return(run) + return _c +} + +// PublishStream provides a mock function with given fields: ctx, opts +func (_m *mockPubSubClient) PublishStream(ctx context.Context, opts ...grpc.CallOption) (eventbusv1.PubSub_PublishStreamClient, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for PublishStream") + } + + var r0 eventbusv1.PubSub_PublishStreamClient + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) (eventbusv1.PubSub_PublishStreamClient, error)); ok { + return rf(ctx, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) eventbusv1.PubSub_PublishStreamClient); ok { + r0 = rf(ctx, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(eventbusv1.PubSub_PublishStreamClient) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ...grpc.CallOption) error); ok { + r1 = rf(ctx, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// mockPubSubClient_PublishStream_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PublishStream' +type mockPubSubClient_PublishStream_Call struct { + *mock.Call +} + +// PublishStream is a helper method to define mock.On call +// - ctx context.Context +// - opts ...grpc.CallOption +func (_e *mockPubSubClient_Expecter) PublishStream(ctx interface{}, opts ...interface{}) *mockPubSubClient_PublishStream_Call { + return &mockPubSubClient_PublishStream_Call{Call: _e.mock.On("PublishStream", + append([]interface{}{ctx}, opts...)...)} +} + +func (_c *mockPubSubClient_PublishStream_Call) Run(run func(ctx context.Context, opts ...grpc.CallOption)) *mockPubSubClient_PublishStream_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-1) + for i, a := range args[1:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), variadicArgs...) + }) + return _c +} + +func (_c *mockPubSubClient_PublishStream_Call) Return(_a0 eventbusv1.PubSub_PublishStreamClient, _a1 error) *mockPubSubClient_PublishStream_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *mockPubSubClient_PublishStream_Call) RunAndReturn(run func(context.Context, ...grpc.CallOption) (eventbusv1.PubSub_PublishStreamClient, error)) *mockPubSubClient_PublishStream_Call { + _c.Call.Return(run) + return _c +} + +// Subscribe provides a mock function with given fields: ctx, opts +func (_m *mockPubSubClient) Subscribe(ctx context.Context, opts ...grpc.CallOption) (eventbusv1.PubSub_SubscribeClient, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Subscribe") + } + + var r0 eventbusv1.PubSub_SubscribeClient + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) (eventbusv1.PubSub_SubscribeClient, error)); ok { + return rf(ctx, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) eventbusv1.PubSub_SubscribeClient); ok { + r0 = rf(ctx, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(eventbusv1.PubSub_SubscribeClient) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ...grpc.CallOption) error); ok { + r1 = rf(ctx, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// mockPubSubClient_Subscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscribe' +type mockPubSubClient_Subscribe_Call struct { + *mock.Call +} + +// Subscribe is a helper method to define mock.On call +// - ctx context.Context +// - opts ...grpc.CallOption +func (_e *mockPubSubClient_Expecter) Subscribe(ctx interface{}, opts ...interface{}) *mockPubSubClient_Subscribe_Call { + return &mockPubSubClient_Subscribe_Call{Call: _e.mock.On("Subscribe", + append([]interface{}{ctx}, opts...)...)} +} + +func (_c *mockPubSubClient_Subscribe_Call) Run(run func(ctx context.Context, opts ...grpc.CallOption)) *mockPubSubClient_Subscribe_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-1) + for i, a := range args[1:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), variadicArgs...) + }) + return _c +} + +func (_c *mockPubSubClient_Subscribe_Call) Return(_a0 eventbusv1.PubSub_SubscribeClient, _a1 error) *mockPubSubClient_Subscribe_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *mockPubSubClient_Subscribe_Call) RunAndReturn(run func(context.Context, ...grpc.CallOption) (eventbusv1.PubSub_SubscribeClient, error)) *mockPubSubClient_Subscribe_Call { + _c.Call.Return(run) + return _c +} + +// newMockPubSubClient creates a new instance of mockPubSubClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func newMockPubSubClient(t interface { + mock.TestingT + Cleanup(func()) +}) *mockPubSubClient { + mock := &mockPubSubClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/source_pubsub/mock_pub_sub_subscribe_client_test.go b/source_pubsub/mock_pub_sub_subscribe_client_test.go new file mode 100644 index 0000000..d6bbf2c --- /dev/null +++ b/source_pubsub/mock_pub_sub_subscribe_client_test.go @@ -0,0 +1,430 @@ +// Code generated by mockery. DO NOT EDIT. + +package source + +import ( + context "context" + + eventbusv1 "github.com/conduitio-labs/conduit-connector-salesforce/proto/eventbus/v1" + metadata "google.golang.org/grpc/metadata" + + mock "github.com/stretchr/testify/mock" +) + +// mockPubSub_SubscribeClient is an autogenerated mock type for the PubSub_SubscribeClient type +type mockPubSub_SubscribeClient struct { + mock.Mock +} + +type mockPubSub_SubscribeClient_Expecter struct { + mock *mock.Mock +} + +func (_m *mockPubSub_SubscribeClient) EXPECT() *mockPubSub_SubscribeClient_Expecter { + return &mockPubSub_SubscribeClient_Expecter{mock: &_m.Mock} +} + +// CloseSend provides a mock function with given fields: +func (_m *mockPubSub_SubscribeClient) CloseSend() error { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for CloseSend") + } + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockPubSub_SubscribeClient_CloseSend_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CloseSend' +type mockPubSub_SubscribeClient_CloseSend_Call struct { + *mock.Call +} + +// CloseSend is a helper method to define mock.On call +func (_e *mockPubSub_SubscribeClient_Expecter) CloseSend() *mockPubSub_SubscribeClient_CloseSend_Call { + return &mockPubSub_SubscribeClient_CloseSend_Call{Call: _e.mock.On("CloseSend")} +} + +func (_c *mockPubSub_SubscribeClient_CloseSend_Call) Run(run func()) *mockPubSub_SubscribeClient_CloseSend_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *mockPubSub_SubscribeClient_CloseSend_Call) Return(_a0 error) *mockPubSub_SubscribeClient_CloseSend_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockPubSub_SubscribeClient_CloseSend_Call) RunAndReturn(run func() error) *mockPubSub_SubscribeClient_CloseSend_Call { + _c.Call.Return(run) + return _c +} + +// Context provides a mock function with given fields: +func (_m *mockPubSub_SubscribeClient) Context() context.Context { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Context") + } + + var r0 context.Context + if rf, ok := ret.Get(0).(func() context.Context); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(context.Context) + } + } + + return r0 +} + +// mockPubSub_SubscribeClient_Context_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Context' +type mockPubSub_SubscribeClient_Context_Call struct { + *mock.Call +} + +// Context is a helper method to define mock.On call +func (_e *mockPubSub_SubscribeClient_Expecter) Context() *mockPubSub_SubscribeClient_Context_Call { + return &mockPubSub_SubscribeClient_Context_Call{Call: _e.mock.On("Context")} +} + +func (_c *mockPubSub_SubscribeClient_Context_Call) Run(run func()) *mockPubSub_SubscribeClient_Context_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *mockPubSub_SubscribeClient_Context_Call) Return(_a0 context.Context) *mockPubSub_SubscribeClient_Context_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockPubSub_SubscribeClient_Context_Call) RunAndReturn(run func() context.Context) *mockPubSub_SubscribeClient_Context_Call { + _c.Call.Return(run) + return _c +} + +// Header provides a mock function with given fields: +func (_m *mockPubSub_SubscribeClient) Header() (metadata.MD, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Header") + } + + var r0 metadata.MD + var r1 error + if rf, ok := ret.Get(0).(func() (metadata.MD, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() metadata.MD); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(metadata.MD) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// mockPubSub_SubscribeClient_Header_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Header' +type mockPubSub_SubscribeClient_Header_Call struct { + *mock.Call +} + +// Header is a helper method to define mock.On call +func (_e *mockPubSub_SubscribeClient_Expecter) Header() *mockPubSub_SubscribeClient_Header_Call { + return &mockPubSub_SubscribeClient_Header_Call{Call: _e.mock.On("Header")} +} + +func (_c *mockPubSub_SubscribeClient_Header_Call) Run(run func()) *mockPubSub_SubscribeClient_Header_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *mockPubSub_SubscribeClient_Header_Call) Return(_a0 metadata.MD, _a1 error) *mockPubSub_SubscribeClient_Header_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *mockPubSub_SubscribeClient_Header_Call) RunAndReturn(run func() (metadata.MD, error)) *mockPubSub_SubscribeClient_Header_Call { + _c.Call.Return(run) + return _c +} + +// Recv provides a mock function with given fields: +func (_m *mockPubSub_SubscribeClient) Recv() (*eventbusv1.FetchResponse, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Recv") + } + + var r0 *eventbusv1.FetchResponse + var r1 error + if rf, ok := ret.Get(0).(func() (*eventbusv1.FetchResponse, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() *eventbusv1.FetchResponse); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*eventbusv1.FetchResponse) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// mockPubSub_SubscribeClient_Recv_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Recv' +type mockPubSub_SubscribeClient_Recv_Call struct { + *mock.Call +} + +// Recv is a helper method to define mock.On call +func (_e *mockPubSub_SubscribeClient_Expecter) Recv() *mockPubSub_SubscribeClient_Recv_Call { + return &mockPubSub_SubscribeClient_Recv_Call{Call: _e.mock.On("Recv")} +} + +func (_c *mockPubSub_SubscribeClient_Recv_Call) Run(run func()) *mockPubSub_SubscribeClient_Recv_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *mockPubSub_SubscribeClient_Recv_Call) Return(_a0 *eventbusv1.FetchResponse, _a1 error) *mockPubSub_SubscribeClient_Recv_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *mockPubSub_SubscribeClient_Recv_Call) RunAndReturn(run func() (*eventbusv1.FetchResponse, error)) *mockPubSub_SubscribeClient_Recv_Call { + _c.Call.Return(run) + return _c +} + +// RecvMsg provides a mock function with given fields: m +func (_m *mockPubSub_SubscribeClient) RecvMsg(m interface{}) error { + ret := _m.Called(m) + + if len(ret) == 0 { + panic("no return value specified for RecvMsg") + } + + var r0 error + if rf, ok := ret.Get(0).(func(interface{}) error); ok { + r0 = rf(m) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockPubSub_SubscribeClient_RecvMsg_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RecvMsg' +type mockPubSub_SubscribeClient_RecvMsg_Call struct { + *mock.Call +} + +// RecvMsg is a helper method to define mock.On call +// - m interface{} +func (_e *mockPubSub_SubscribeClient_Expecter) RecvMsg(m interface{}) *mockPubSub_SubscribeClient_RecvMsg_Call { + return &mockPubSub_SubscribeClient_RecvMsg_Call{Call: _e.mock.On("RecvMsg", m)} +} + +func (_c *mockPubSub_SubscribeClient_RecvMsg_Call) Run(run func(m interface{})) *mockPubSub_SubscribeClient_RecvMsg_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(interface{})) + }) + return _c +} + +func (_c *mockPubSub_SubscribeClient_RecvMsg_Call) Return(_a0 error) *mockPubSub_SubscribeClient_RecvMsg_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockPubSub_SubscribeClient_RecvMsg_Call) RunAndReturn(run func(interface{}) error) *mockPubSub_SubscribeClient_RecvMsg_Call { + _c.Call.Return(run) + return _c +} + +// Send provides a mock function with given fields: _a0 +func (_m *mockPubSub_SubscribeClient) Send(_a0 *eventbusv1.FetchRequest) error { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for Send") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*eventbusv1.FetchRequest) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockPubSub_SubscribeClient_Send_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Send' +type mockPubSub_SubscribeClient_Send_Call struct { + *mock.Call +} + +// Send is a helper method to define mock.On call +// - _a0 *eventbusv1.FetchRequest +func (_e *mockPubSub_SubscribeClient_Expecter) Send(_a0 interface{}) *mockPubSub_SubscribeClient_Send_Call { + return &mockPubSub_SubscribeClient_Send_Call{Call: _e.mock.On("Send", _a0)} +} + +func (_c *mockPubSub_SubscribeClient_Send_Call) Run(run func(_a0 *eventbusv1.FetchRequest)) *mockPubSub_SubscribeClient_Send_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*eventbusv1.FetchRequest)) + }) + return _c +} + +func (_c *mockPubSub_SubscribeClient_Send_Call) Return(_a0 error) *mockPubSub_SubscribeClient_Send_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockPubSub_SubscribeClient_Send_Call) RunAndReturn(run func(*eventbusv1.FetchRequest) error) *mockPubSub_SubscribeClient_Send_Call { + _c.Call.Return(run) + return _c +} + +// SendMsg provides a mock function with given fields: m +func (_m *mockPubSub_SubscribeClient) SendMsg(m interface{}) error { + ret := _m.Called(m) + + if len(ret) == 0 { + panic("no return value specified for SendMsg") + } + + var r0 error + if rf, ok := ret.Get(0).(func(interface{}) error); ok { + r0 = rf(m) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockPubSub_SubscribeClient_SendMsg_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendMsg' +type mockPubSub_SubscribeClient_SendMsg_Call struct { + *mock.Call +} + +// SendMsg is a helper method to define mock.On call +// - m interface{} +func (_e *mockPubSub_SubscribeClient_Expecter) SendMsg(m interface{}) *mockPubSub_SubscribeClient_SendMsg_Call { + return &mockPubSub_SubscribeClient_SendMsg_Call{Call: _e.mock.On("SendMsg", m)} +} + +func (_c *mockPubSub_SubscribeClient_SendMsg_Call) Run(run func(m interface{})) *mockPubSub_SubscribeClient_SendMsg_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(interface{})) + }) + return _c +} + +func (_c *mockPubSub_SubscribeClient_SendMsg_Call) Return(_a0 error) *mockPubSub_SubscribeClient_SendMsg_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockPubSub_SubscribeClient_SendMsg_Call) RunAndReturn(run func(interface{}) error) *mockPubSub_SubscribeClient_SendMsg_Call { + _c.Call.Return(run) + return _c +} + +// Trailer provides a mock function with given fields: +func (_m *mockPubSub_SubscribeClient) Trailer() metadata.MD { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Trailer") + } + + var r0 metadata.MD + if rf, ok := ret.Get(0).(func() metadata.MD); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(metadata.MD) + } + } + + return r0 +} + +// mockPubSub_SubscribeClient_Trailer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Trailer' +type mockPubSub_SubscribeClient_Trailer_Call struct { + *mock.Call +} + +// Trailer is a helper method to define mock.On call +func (_e *mockPubSub_SubscribeClient_Expecter) Trailer() *mockPubSub_SubscribeClient_Trailer_Call { + return &mockPubSub_SubscribeClient_Trailer_Call{Call: _e.mock.On("Trailer")} +} + +func (_c *mockPubSub_SubscribeClient_Trailer_Call) Run(run func()) *mockPubSub_SubscribeClient_Trailer_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *mockPubSub_SubscribeClient_Trailer_Call) Return(_a0 metadata.MD) *mockPubSub_SubscribeClient_Trailer_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockPubSub_SubscribeClient_Trailer_Call) RunAndReturn(run func() metadata.MD) *mockPubSub_SubscribeClient_Trailer_Call { + _c.Call.Return(run) + return _c +} + +// newMockPubSub_SubscribeClient creates a new instance of mockPubSub_SubscribeClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func newMockPubSub_SubscribeClient(t interface { + mock.TestingT + Cleanup(func()) +}) *mockPubSub_SubscribeClient { + mock := &mockPubSub_SubscribeClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/source_pubsub/oauth.go b/source_pubsub/oauth.go new file mode 100644 index 0000000..b09a084 --- /dev/null +++ b/source_pubsub/oauth.go @@ -0,0 +1,167 @@ +// Copyright © 2022 Meroxa, Inc. and Miquido +// +// 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 source + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/url" + "strings" + "time" +) + +type authenticator interface { + Login() (*LoginResponse, error) + UserInfo(string) (*UserInfoResponse, error) +} + +const ( + loginEndpoint = "/services/oauth2/token" + userInfoEndpoint = "/services/oauth2/userinfo" +) + +var OAuthDialTimeout = 5 * time.Second + +type LoginResponse struct { + AccessToken string `json:"access_token"` + InstanceURL string `json:"instance_url"` + ID string `json:"id"` + TokenType string `json:"token_type"` + IssuedAt string `json:"issued_at"` + Signature string `json:"signature"` + Error string `json:"error"` + ErrorDescription string `json:"error_description"` +} + +func (l LoginResponse) Err() error { + return fmt.Errorf("%s: %s", l.Error, l.ErrorDescription) +} + +type UserInfoResponse struct { + UserID string `json:"user_id"` + OrganizationID string `json:"organization_id"` + Error string `json:"error"` + ErrorDescription string `json:"error_description"` +} + +func (u UserInfoResponse) Err() error { + return fmt.Errorf("%s: %s", u.Error, u.ErrorDescription) +} + +type Credentials struct { + ClientID, ClientSecret string + OAuthEndpoint *url.URL +} + +func NewCredentials(clientID, secret, endpoint string) (Credentials, error) { + u, err := url.Parse(endpoint) + if err != nil { + return Credentials{}, fmt.Errorf("failed to parse oauth endpoint url: %w", err) + } + + return Credentials{ + ClientID: clientID, + ClientSecret: secret, + OAuthEndpoint: u, + }, nil +} + +type oauth struct { + Credentials +} + +func (a oauth) Login() (*LoginResponse, error) { + body := url.Values{} + body.Set("grant_type", "client_credentials") + body.Set("client_id", a.ClientID) + body.Set("client_secret", a.ClientSecret) + + ctx, cancelFn := context.WithTimeout(context.Background(), OAuthDialTimeout) + defer cancelFn() + + req, err := http.NewRequestWithContext( + ctx, + http.MethodPost, + a.loginURL(), + strings.NewReader(body.Encode()), + ) + if err != nil { + return nil, fmt.Errorf("failed to make login req: %w", err) + } + + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + + httpResp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, fmt.Errorf("http oauth request failed: %w", err) + } + defer httpResp.Body.Close() + + var loginResp LoginResponse + if err := json.NewDecoder(httpResp.Body).Decode(&loginResp); err != nil { + return nil, fmt.Errorf("error decoding login response: %w", err) + } + + if httpResp.StatusCode != http.StatusOK { + return nil, fmt.Errorf( + "unexpected oauth login (status: %d) response: %w", httpResp.StatusCode, loginResp.Err(), + ) + } + + return &loginResp, nil +} + +func (a oauth) UserInfo(accessToken string) (*UserInfoResponse, error) { + ctx, cancel := context.WithTimeout(context.Background(), OAuthDialTimeout) + defer cancel() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, a.userInfoURL(), nil) + if err != nil { + return nil, fmt.Errorf("failed to make userinfo req: %w", err) + } + + req.Header.Set("Authorization", "Bearer "+accessToken) + + httpResp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, fmt.Errorf("error getting user info response - %s", err) + } + + defer httpResp.Body.Close() + + var userInfoResp UserInfoResponse + err = json.NewDecoder(httpResp.Body).Decode(&userInfoResp) + if err != nil { + return nil, fmt.Errorf("error decoding user info - %s", err) + } + + if httpResp.StatusCode != http.StatusOK { + return nil, fmt.Errorf( + "unexpected oauth userInfo (status: %d) response: %w", httpResp.StatusCode, userInfoResp.Err(), + ) + } + + return &userInfoResp, nil +} + +func (a oauth) loginURL() string { + return a.OAuthEndpoint.JoinPath(loginEndpoint).String() +} + +func (a oauth) userInfoURL() string { + return a.OAuthEndpoint.JoinPath(userInfoEndpoint).String() +} diff --git a/source_pubsub/paramgen_config.go b/source_pubsub/paramgen_config.go new file mode 100644 index 0000000..2a034ce --- /dev/null +++ b/source_pubsub/paramgen_config.go @@ -0,0 +1,101 @@ +// Code generated by paramgen. DO NOT EDIT. +// Source: github.com/ConduitIO/conduit-commons/tree/main/paramgen + +package source + +import ( + "github.com/conduitio/conduit-commons/config" +) + +const ( + ConfigClientID = "clientID" + ConfigClientSecret = "clientSecret" + ConfigInsecureSkipVerify = "insecureSkipVerify" + ConfigOauthEndpoint = "oauthEndpoint" + ConfigPollingPeriod = "pollingPeriod" + ConfigPubsubAddress = "pubsubAddress" + ConfigReplayPreset = "replayPreset" + ConfigRetryCount = "retryCount" + ConfigTopicName = "topicName" + ConfigTopicNames = "topicNames" + ConfigUsername = "username" +) + +func (Config) Parameters() map[string]config.Parameter { + return map[string]config.Parameter{ + ConfigClientID: { + Default: "", + Description: "ClientID is the client id from the salesforce app", + Type: config.ParameterTypeString, + Validations: []config.Validation{ + config.ValidationRequired{}, + }, + }, + ConfigClientSecret: { + Default: "", + Description: "ClientSecret is the client secret from the salesforce app", + Type: config.ParameterTypeString, + Validations: []config.Validation{ + config.ValidationRequired{}, + }, + }, + ConfigInsecureSkipVerify: { + Default: "false", + Description: "InsecureSkipVerify disables certificate validation", + Type: config.ParameterTypeBool, + Validations: []config.Validation{}, + }, + ConfigOauthEndpoint: { + Default: "", + Description: "OAuthEndpoint is the OAuthEndpoint from the salesforce app", + Type: config.ParameterTypeString, + Validations: []config.Validation{ + config.ValidationRequired{}, + }, + }, + ConfigPollingPeriod: { + Default: "100ms", + Description: "PollingPeriod is the client event polling interval", + Type: config.ParameterTypeDuration, + Validations: []config.Validation{}, + }, + ConfigPubsubAddress: { + Default: "api.pubsub.salesforce.com:7443", + Description: "gRPC Pubsub Salesforce API address", + Type: config.ParameterTypeString, + Validations: []config.Validation{}, + }, + ConfigReplayPreset: { + Default: "earliest", + Description: "Replay preset for the position the connector is fetching events from, can be latest or default to earliest.", + Type: config.ParameterTypeString, + Validations: []config.Validation{}, + }, + ConfigRetryCount: { + Default: "10", + Description: "Number of retries allowed per read before the connector errors out", + Type: config.ParameterTypeInt, + Validations: []config.Validation{}, + }, + ConfigTopicName: { + Default: "", + Description: "TopicName {WARN will be deprecated soon} the TopicName the source connector will subscribe to", + Type: config.ParameterTypeString, + Validations: []config.Validation{}, + }, + ConfigTopicNames: { + Default: "", + Description: "TopicNames are the TopicNames the source connector will subscribe to", + Type: config.ParameterTypeString, + Validations: []config.Validation{ + config.ValidationRequired{}, + }, + }, + ConfigUsername: { + Default: "", + Description: "Deprecated: Username is the client secret from the salesforce app.", + Type: config.ParameterTypeString, + Validations: []config.Validation{}, + }, + } +} diff --git a/source_pubsub/position/position.go b/source_pubsub/position/position.go new file mode 100644 index 0000000..d044895 --- /dev/null +++ b/source_pubsub/position/position.go @@ -0,0 +1,90 @@ +package position + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/conduitio/conduit-commons/opencdc" +) + +type Topics struct { + Topics TopicPositions `json:"topics"` +} + +type TopicPositions map[string]TopicPosition + +type TopicPosition struct { + ReplayID []byte `json:"replayID"` + ReadTime time.Time `json:"readTime"` +} + +func ParseSDKPosition(sdkPos opencdc.Position, topic string) (Topics, error) { + var p Topics + p.Topics = make(TopicPositions) + + if len(sdkPos) == 0 { + return p, nil + } + + err := json.Unmarshal(sdkPos, &p) + if err != nil { + if topic == "" { + return p, fmt.Errorf("could not parsed sdk position %v: %w", sdkPos, err) + } + + p.SetTopics([]string{topic}) + err := p.SetTopicReplayID(topic, sdkPos) + return p, err + } + + return p, err +} + +func NewTopicPosition() Topics { + var p Topics + p.Topics = make(TopicPositions) + return p +} + +func (p Topics) SetTopics(topics []string) { + for _, topic := range topics { + if _, ok := p.Topics[topic]; !ok { + p.Topics[topic] = TopicPosition{ + ReplayID: nil, + } + } + } +} + +func (p Topics) TopicReplayID(topic string) []byte { + if p.Topics != nil { + if _, ok := p.Topics[topic]; ok { + return p.Topics[topic].ReplayID + } + } + return nil +} + +func (p Topics) SetTopicReplayID(topic string, replayID []byte) error { + if p.Topics != nil { + if _, ok := p.Topics[topic]; ok { + p.Topics[topic] = TopicPosition{ + ReplayID: replayID, + ReadTime: time.Now(), + } + } else { + // should never be even reaching this point, something went wrong if we do + return fmt.Errorf("attempting to set replay id - %b on topic %s, topic doesn't exist on position", replayID, topic) + } + } + return nil +} + +func (p Topics) ToSDKPosition() opencdc.Position { + v, err := json.Marshal(p) + if err != nil { + panic(err) + } + return v +} diff --git a/source_pubsub/source.go b/source_pubsub/source.go new file mode 100644 index 0000000..b40525f --- /dev/null +++ b/source_pubsub/source.go @@ -0,0 +1,176 @@ +// Copyright © 2022 Meroxa, Inc. +// +// 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 source + +import ( + "context" + "encoding/base64" + "fmt" + + "github.com/conduitio-labs/conduit-connector-salesforce/source_pubsub/position" + "github.com/conduitio/conduit-commons/config" + "github.com/conduitio/conduit-commons/opencdc" + sdk "github.com/conduitio/conduit-connector-sdk" +) + +type client interface { + Next(context.Context) (opencdc.Record, error) + Initialize(context.Context) error + Stop(context.Context) + Close(context.Context) error + Wait(context.Context) error +} + +var _ client = (*PubSubClient)(nil) + +type Source struct { + sdk.UnimplementedSource + client client + config Config +} + +func NewSource() sdk.Source { + return sdk.SourceWithMiddleware(&Source{}, sdk.DefaultSourceMiddleware()...) +} + +func (s *Source) Parameters() config.Parameters { + return s.config.Parameters() +} + +func (s *Source) Configure(ctx context.Context, cfg config.Config) error { + var config Config + + if err := sdk.Util.ParseConfig( + ctx, + cfg, + &s.config, + NewSource().Parameters(), + ); err != nil { + return fmt.Errorf("failed to parse config: %w", err) + } + + config, err := config.Validate(ctx) + if err != nil { + return fmt.Errorf("config failed to validate: %w", err) + } + + s.config = config + + return nil +} + +func (s *Source) Open(ctx context.Context, sdkPos opencdc.Position) error { + logger := sdk.Logger(ctx) + + var parsedPositions position.Topics + + logger.Debug(). + Str("at", "source.open"). + Str("position", base64.StdEncoding.EncodeToString(sdkPos)). + Strs("topics", s.config.TopicNames). + Msg("Open Source Connector") + + parsedPositions, err := position.ParseSDKPosition(sdkPos, s.config.TopicName) + if err != nil { + return fmt.Errorf("error parsing sdk position: %w", err) + } + + client, err := NewGRPCClient(ctx, s.config, parsedPositions) + if err != nil { + return fmt.Errorf("could not create GRPCClient: %w", err) + } + + if err := client.Initialize(ctx); err != nil { + return fmt.Errorf("could not initialize pubsub client: %w", err) + } + + s.client = client + + for _, t := range s.config.TopicNames { + p := parsedPositions.TopicReplayID(t) + logger.Debug(). + Str("at", "source.open"). + Str("position", string(p)). + Str("position encoded", base64.StdEncoding.EncodeToString(p)). + Str("topic", t). + Msgf("Grpc Client has been set. Will begin read for topic: %s", t) + } + + return nil +} + +func (s *Source) Read(ctx context.Context) (rec opencdc.Record, err error) { + logger := sdk.Logger(ctx) + logger.Debug(). + Strs("topics", s.config.TopicNames). + Msg("begin read") + + r, err := s.client.Next(ctx) + if err != nil { + return opencdc.Record{}, fmt.Errorf("failed to get next record: %w", err) + } + + // filter out empty record payloads + if r.Payload.Before == nil && r.Payload.After == nil { + logger.Error(). + Interface("record", r). + Msg("backing off, empty record payload detected") + + return opencdc.Record{}, sdk.ErrBackoffRetry + } + + topic, err := r.Metadata.GetCollection() + if err != nil { + return opencdc.Record{}, err + } + + logger.Debug(). + Str("at", "source.read"). + Str("position encoded", base64.StdEncoding.EncodeToString(r.Position)). + Str("position", string(r.Position)). + Str("record on topic", topic). + Msg("sending record") + + return r, nil +} + +func (s *Source) Ack(ctx context.Context, pos opencdc.Position) error { + sdk.Logger(ctx).Debug(). + Str("at", "source.ack"). + Str("uncoded position ", string(pos)). + Str("position", base64.StdEncoding.EncodeToString(pos)). + Msg("received ack") + + return nil +} + +func (s *Source) Teardown(ctx context.Context) error { + if s.client == nil { + return nil + } + + s.client.Stop(ctx) + + if err := s.client.Wait(ctx); err != nil { + sdk.Logger(ctx).Error().Err(err). + Msg("received error while stopping client") + } + + if err := s.client.Close(ctx); err != nil { + return fmt.Errorf("error when closing subscriber conn: %w", err) + } + + return nil +} diff --git a/source_pubsub/source_test.go b/source_pubsub/source_test.go new file mode 100644 index 0000000..b228479 --- /dev/null +++ b/source_pubsub/source_test.go @@ -0,0 +1,124 @@ +// Copyright © 2022 Meroxa, Inc. and Miquido +// +// 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 source + +import ( + "context" + "errors" + "testing" + + "github.com/conduitio/conduit-commons/opencdc" + sdk "github.com/conduitio/conduit-connector-sdk" + mock "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func Test_Read(t *testing.T) { + testRecord := opencdc.Record{ + Position: []byte("test1"), + Operation: opencdc.OperationCreate, + Metadata: opencdc.Metadata{ + "test1": "test", + "opencdc.collection": "test", + }, + Key: opencdc.StructuredData{ + "test1": "test", + }, + Payload: opencdc.Change{ + After: opencdc.StructuredData{ + "test1": "test", + }, + }, + } + + testConfig := Config{ + ClientID: "test-client-id", + ClientSecret: "test-client-secret", + OAuthEndpoint: "https://somewhere", + TopicNames: []string{"/events/TestEvent__e", "/events/TestEvent2__e"}, + } + + testCases := []struct { + desc string + config Config + mockClient func() *mockClient + expectedRecord opencdc.Record + expectedErr error + }{ + { + desc: "success - receive event", + config: testConfig, + mockClient: func() *mockClient { + m := newMockClient(t) + m.On("Next", mock.Anything).Return(testRecord, nil) + + return m + }, + expectedRecord: testRecord, + }, + { + desc: "success - no event, backoff", + config: testConfig, + mockClient: func() *mockClient { + m := newMockClient(t) + m.On("Next", mock.Anything).Return(opencdc.Record{}, nil).Times(1) + return m + }, + expectedErr: sdk.ErrBackoffRetry, + }, + + { + desc: "error - failed on Next", + config: testConfig, + mockClient: func() *mockClient { + m := newMockClient(t) + m.On("Next", mock.Anything).Return(opencdc.Record{}, errors.New("error receiving new events - test error")).Times(1) + return m + }, + expectedErr: errors.New("error receiving new events - test error"), + }, + { + desc: "error - record with empty payload", + config: testConfig, + mockClient: func() *mockClient { + m := newMockClient(t) + m.On("Next", mock.Anything).Return(opencdc.Record{Payload: opencdc.Change{Before: nil, After: nil}}, nil).Times(1) + return m + }, + expectedErr: sdk.ErrBackoffRetry, + }, + } + + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + ctx := context.Background() + s := Source{ + config: tc.config, + } + if tc.mockClient != nil { + s.client = tc.mockClient() + } + + r, err := s.Read(ctx) + if tc.expectedErr != nil { + require.Error(t, err) + require.ErrorContains(t, err, tc.expectedErr.Error()) + } else { + require.NoError(t, err) + require.Equal(t, tc.expectedRecord, r) + } + }) + } +} diff --git a/tools.go b/tools.go index f6e5173..0f81a2c 100644 --- a/tools.go +++ b/tools.go @@ -17,5 +17,8 @@ package main import ( + _ "github.com/conduitio/conduit-commons/paramgen" + _ "github.com/daixiang0/gci" _ "github.com/golangci/golangci-lint/cmd/golangci-lint" + _ "mvdan.cc/gofumpt" )