├── .github
├── CODEOWNERS
├── dependabot.yml
└── workflows
│ ├── conformance.yaml
│ ├── go-build.yaml
│ ├── go-format.yaml
│ ├── go-lint.yaml
│ ├── go-unit-test.yaml
│ ├── inclusive.yaml
│ ├── integration.yaml
│ ├── observability.yaml
│ ├── release.yaml
│ └── update-dependencies.yml
├── .gitignore
├── .gitmodules
├── .golangci.yaml
├── CONTRIBUTING.md
├── LICENSE
├── MAINTAINERS.md
├── README.md
├── RELEASING.md
├── binding
└── format
│ └── protobuf
│ └── v2
│ ├── datacodec.go
│ ├── go.mod
│ ├── go.sum
│ ├── pb
│ ├── cloudevent.pb.go
│ ├── cloudevent.proto
│ └── gen.go
│ ├── protobuf.go
│ └── protobuf_test.go
├── docs
├── Gemfile
├── Gemfile.lock
├── _config.yml
├── concepts.md
├── event_data_structure.md
├── images
│ ├── Makefile
│ ├── forwarder.dot
│ ├── forwarder.svg
│ ├── mutator.dot
│ ├── mutator.svg
│ ├── receiver.dot
│ ├── receiver.svg
│ ├── sender.dot
│ ├── sender.svg
│ ├── stack.dot
│ └── stack.svg
├── index.md
└── protocol_implementations.md
├── hack
├── boilerplate
│ ├── add-boilerplate.sh
│ ├── boilerplate.go.txt
│ └── boilerplate.sh.txt
├── build-test.sh
├── conformance-test.sh
├── go-mod-tidy.sh
├── integration-test.sh
├── observability-test.sh
├── run-integration-services.sh
├── tag-release.sh
├── unit-test.sh
└── update-deps.sh
├── maintainer_guidelines.md
├── observability
├── opencensus
│ └── v2
│ │ ├── client
│ │ ├── client.go
│ │ ├── client_test.go
│ │ ├── observability_service.go
│ │ ├── observable.go
│ │ ├── reporter.go
│ │ └── trace_attributes.go
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── http
│ │ └── http.go
└── opentelemetry
│ └── v2
│ ├── README.md
│ ├── client
│ ├── client.go
│ ├── cloudevents_carrier.go
│ ├── otel_observability_service.go
│ └── otel_options.go
│ ├── go.mod
│ ├── go.sum
│ └── http
│ └── http.go
├── pr_guidelines.md
├── protocol
├── amqp
│ └── v2
│ │ ├── doc.go
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── message.go
│ │ ├── message_test.go
│ │ ├── options.go
│ │ ├── protocol.go
│ │ ├── receiver.go
│ │ ├── sender.go
│ │ ├── types.go
│ │ └── write_message.go
├── kafka_confluent
│ └── v2
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── message.go
│ │ ├── message_test.go
│ │ ├── option.go
│ │ ├── protocol.go
│ │ ├── protocol_test.go
│ │ ├── write_producer_message.go
│ │ └── write_producer_message_test.go
├── kafka_sarama
│ └── v2
│ │ ├── doc.go
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── message.go
│ │ ├── message_benchmark_test.go
│ │ ├── message_test.go
│ │ ├── option.go
│ │ ├── protocol.go
│ │ ├── receiver.go
│ │ ├── sender.go
│ │ ├── sender_test.go
│ │ ├── write_producer_message.go
│ │ ├── write_producer_message_benchmark_test.go
│ │ └── write_producer_message_test.go
├── mqtt_paho
│ └── v2
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── message.go
│ │ ├── message_test.go
│ │ ├── option.go
│ │ ├── protocol.go
│ │ ├── write_message.go
│ │ └── write_message_test.go
├── nats
│ └── v2
│ │ ├── doc.go
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── message.go
│ │ ├── options.go
│ │ ├── options_test.go
│ │ ├── protocol.go
│ │ ├── receiver.go
│ │ ├── sender.go
│ │ ├── subscriber.go
│ │ └── write_message.go
├── nats_jetstream
│ ├── v2
│ │ ├── doc.go
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── message.go
│ │ ├── message_test.go
│ │ ├── options.go
│ │ ├── options_test.go
│ │ ├── protocol.go
│ │ ├── receiver.go
│ │ ├── sender.go
│ │ ├── subscriber.go
│ │ └── write_message.go
│ └── v3
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── message.go
│ │ ├── message_test.go
│ │ ├── options.go
│ │ ├── options_test.go
│ │ ├── protocol.go
│ │ ├── protocol_test.go
│ │ ├── validation.go
│ │ ├── validation_test.go
│ │ ├── write_message.go
│ │ └── write_message_test.go
├── pubsub
│ └── v2
│ │ ├── attributes.go
│ │ ├── context
│ │ └── context.go
│ │ ├── doc.go
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── internal
│ │ ├── connection.go
│ │ └── connection_test.go
│ │ ├── message.go
│ │ ├── message_test.go
│ │ ├── options.go
│ │ ├── protocol.go
│ │ ├── protocol_test.go
│ │ └── write_pubsub_message.go
├── stan
│ └── v2
│ │ ├── context.go
│ │ ├── context_test.go
│ │ ├── doc.go
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── message.go
│ │ ├── options.go
│ │ ├── options_test.go
│ │ ├── protocol.go
│ │ ├── receiver.go
│ │ ├── sender.go
│ │ ├── subscriber.go
│ │ └── write_message.go
└── ws
│ └── v2
│ ├── client_protocol.go
│ ├── client_protocol_test.go
│ ├── context.go
│ ├── doc.go
│ ├── go.mod
│ ├── go.sum
│ ├── subprotocols.go
│ └── subprotocols_test.go
├── samples
├── README.md
├── amqp
│ ├── README.md
│ ├── go.mod
│ ├── go.sum
│ ├── receiver
│ │ └── main.go
│ └── sender
│ │ └── main.go
├── gochan
│ ├── go.mod
│ ├── go.sum
│ └── main.go
├── http
│ ├── go.mod
│ ├── go.sum
│ ├── receiver-direct
│ │ └── main.go
│ ├── receiver-gin
│ │ ├── README.md
│ │ ├── event.json
│ │ └── main.go
│ ├── receiver-gorilla
│ │ └── main.go
│ ├── receiver-protected
│ │ └── main.go
│ ├── receiver-protobuf
│ │ ├── main.go
│ │ ├── sample.pb.go
│ │ └── sample.proto
│ ├── receiver-result
│ │ └── main.go
│ ├── receiver-sleepy
│ │ └── main.go
│ ├── receiver-traced
│ │ └── main.go
│ ├── receiver
│ │ └── main.go
│ ├── requester-with-custom-client
│ │ └── main.go
│ ├── requester
│ │ └── main.go
│ ├── responder
│ │ └── main.go
│ ├── sender-protobuf
│ │ ├── main.go
│ │ ├── sample.pb.go
│ │ └── sample.proto
│ ├── sender-retry
│ │ └── main.go
│ └── sender
│ │ └── main.go
├── kafka
│ ├── README.md
│ ├── go.mod
│ ├── go.sum
│ ├── message-handle-non-cloudevents
│ │ └── main.go
│ ├── receiver
│ │ └── main.go
│ ├── sender-receiver
│ │ └── main.go
│ └── sender
│ │ └── main.go
├── kafka_confluent
│ ├── README.md
│ ├── go.mod
│ ├── go.sum
│ ├── receiver-assign
│ │ └── main.go
│ ├── receiver
│ │ └── main.go
│ └── sender
│ │ └── main.go
├── mqtt
│ ├── README.md
│ ├── go.mod
│ ├── go.sum
│ ├── receiver
│ │ └── main.go
│ └── sender
│ │ └── main.go
├── nats
│ ├── go.mod
│ ├── go.sum
│ ├── message-interoperability
│ │ └── main.go
│ ├── receiver
│ │ └── main.go
│ └── sender
│ │ └── main.go
├── nats_jetstream
│ ├── go.mod
│ ├── go.sum
│ ├── message-interoperability
│ │ └── main.go
│ ├── receiver
│ │ └── main.go
│ ├── sender
│ │ └── main.go
│ └── v3
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── receiver
│ │ └── main.go
│ │ └── sender
│ │ └── main.go
├── pubsub
│ ├── go.mod
│ ├── go.sum
│ ├── multireceiver
│ │ └── main.go
│ ├── multisender
│ │ └── main.go
│ ├── receiver
│ │ └── main.go
│ └── sender
│ │ └── main.go
├── stan
│ ├── go.mod
│ ├── go.sum
│ ├── receiver
│ │ └── main.go
│ ├── sender-receiver
│ │ └── main.go
│ └── sender
│ │ └── main.go
└── ws
│ ├── client
│ └── main.go
│ ├── go.mod
│ └── go.sum
├── sql
└── v2
│ ├── CESQLLexer.g4
│ ├── CESQLParser.g4
│ ├── Makefile
│ ├── README.md
│ ├── errors
│ └── errors.go
│ ├── expression.go
│ ├── expression
│ ├── base_expressions.go
│ ├── comparison_expressions.go
│ ├── exists_expression.go
│ ├── function_invocation_expression.go
│ ├── identifier_expression.go
│ ├── in_expression.go
│ ├── integer_comparison_expressions.go
│ ├── like_expression.go
│ ├── literal_expression.go
│ ├── logic_expressions.go
│ ├── math_expressions.go
│ ├── negate_expression.go
│ └── not_expression.go
│ ├── function.go
│ ├── function
│ ├── casting_functions.go
│ ├── function.go
│ ├── integer_functions.go
│ └── string_functions.go
│ ├── gen
│ ├── CESQLParser.interp
│ ├── CESQLParser.tokens
│ ├── CESQLParserLexer.interp
│ ├── CESQLParserLexer.tokens
│ ├── cesqlparser_base_visitor.go
│ ├── cesqlparser_lexer.go
│ ├── cesqlparser_parser.go
│ └── cesqlparser_visitor.go
│ ├── go.mod
│ ├── go.sum
│ ├── parser
│ ├── case_changing_stream.go
│ ├── expression_visitor.go
│ └── parser.go
│ ├── runtime
│ ├── functions_resolver.go
│ └── test
│ │ ├── tck
│ │ └── user_defined_functions.yaml
│ │ └── user_defined_functions_test.go
│ ├── test
│ ├── tck
│ │ ├── README.md
│ │ ├── binary_comparison_operators.yaml
│ │ ├── binary_logical_operators.yaml
│ │ ├── binary_math_operators.yaml
│ │ ├── case_sensitivity.yaml
│ │ ├── casting_functions.yaml
│ │ ├── context_attributes_access.yaml
│ │ ├── exists_expression.yaml
│ │ ├── in_expression.yaml
│ │ ├── integer_builtin_functions.yaml
│ │ ├── like_expression.yaml
│ │ ├── literals.yaml
│ │ ├── negate_operator.yaml
│ │ ├── not_operator.yaml
│ │ ├── parse_errors.yaml
│ │ ├── spec_examples.yaml
│ │ ├── string_builtin_functions.yaml
│ │ ├── sub_expression.yaml
│ │ └── subscriptions_api_recreations.yaml
│ └── tck_test.go
│ ├── types.go
│ └── utils
│ ├── casting.go
│ └── event.go
├── test
├── benchmark
│ ├── buffering_vs_to_event
│ │ ├── http_transformers_benchmark_test.go
│ │ └── transformers_benchmark_test.go
│ ├── e2e
│ │ ├── benchmark_case.go
│ │ ├── benchmark_result.go
│ │ ├── doc.go
│ │ └── http
│ │ │ ├── 3d_plot_allocs.gnuplot
│ │ │ ├── 3d_plot_ns.gnuplot
│ │ │ ├── README.md
│ │ │ ├── http_mock.go
│ │ │ ├── main.go
│ │ │ ├── plot_output_senders_allocs.gnuplot
│ │ │ ├── plot_output_senders_ns.gnuplot
│ │ │ ├── plot_parallelism_allocs.gnuplot
│ │ │ ├── plot_parallelism_ns.gnuplot
│ │ │ └── run_revision.sh
│ ├── go.mod
│ ├── go.sum
│ ├── http_request_to_kafka_sarama_encode
│ │ └── benchmark_test.go
│ └── kafka_sarama_to_http_request_encode
│ │ └── benchmark_test.go
├── conformance
│ ├── cloudevents_steps_test.go
│ ├── go.mod
│ ├── go.sum
│ ├── http_steps_test.go
│ ├── kafka_steps_test.go
│ └── run_test.go
├── integration
│ ├── amqp
│ │ └── amqp_test.go
│ ├── amqp_binding
│ │ └── amqp_test.go
│ ├── go.mod
│ ├── go.sum
│ ├── http
│ │ ├── blocking_test.go
│ │ ├── direct.go
│ │ ├── direct_v1_test.go
│ │ ├── doc.go
│ │ ├── loopback.go
│ │ ├── loopback_setters_test.go
│ │ ├── loopback_v03_test.go
│ │ ├── loopback_v1_test.go
│ │ ├── middleware.go
│ │ ├── middleware_v1_test.go
│ │ ├── receiver.go
│ │ ├── receiver_v1_test.go
│ │ ├── responder_v1_test.go
│ │ ├── tap_handler.go
│ │ └── validation.go
│ ├── http_binding
│ │ └── http_test.go
│ ├── kafka_confluent
│ │ └── kafka_test.go
│ ├── kafka_sarama
│ │ └── kafka_test.go
│ ├── kafka_sarama_binding
│ │ └── kafka_test.go
│ ├── mqtt_paho
│ │ ├── concurrent_test.go
│ │ └── mqtt_test.go
│ ├── mqtt_paho_binding
│ │ └── mqtt_test.go
│ ├── nats
│ │ └── nats_test.go
│ ├── nats_jetstream
│ │ ├── nats_test.go
│ │ └── v3
│ │ │ └── nats_test.go
│ └── stan
│ │ └── stan_test.go
├── observability
│ ├── go.mod
│ ├── go.sum
│ └── opentelemetry
│ │ ├── client_test.go
│ │ ├── cloudevents_carrier_test.go
│ │ ├── doc.go
│ │ └── otel_observability_service_test.go
└── sql
│ ├── go.mod
│ ├── go.sum
│ └── shortcircuit_test.go
├── tools
├── go.mod
├── go.sum
└── http
│ └── raw
│ └── main.go
└── v2
├── alias.go
├── binding
├── binary_writer.go
├── buffering
│ ├── acks_before_finish_message.go
│ ├── acks_before_finish_message_test.go
│ ├── binary_buffer_message.go
│ ├── copy_message.go
│ ├── copy_message_benchmark_test.go
│ ├── copy_message_test.go
│ ├── doc.go
│ └── struct_buffer_message.go
├── doc.go
├── encoding.go
├── event_message.go
├── event_message_test.go
├── finish_message.go
├── finish_message_test.go
├── format
│ ├── doc.go
│ ├── format.go
│ └── format_test.go
├── message.go
├── spec
│ ├── attributes.go
│ ├── attributes_test.go
│ ├── doc.go
│ ├── match_exact_version.go
│ ├── match_exact_version_test.go
│ ├── spec.go
│ └── spec_test.go
├── structured_writer.go
├── test
│ ├── doc.go
│ ├── mock_binary_message.go
│ ├── mock_structured_message.go
│ ├── mock_transformer.go
│ ├── mock_unknown_message.go
│ └── transformer.go
├── to_event.go
├── to_event_test.go
├── transformer.go
├── transformer
│ ├── add_metadata.go
│ ├── add_metadata_test.go
│ ├── default_metadata.go
│ ├── default_metadata_test.go
│ ├── delete_metadata.go
│ ├── delete_metadata_test.go
│ ├── doc.go
│ ├── set_metadata.go
│ ├── set_metadata_test.go
│ ├── version.go
│ └── version_test.go
├── utils
│ ├── structured_message.go
│ ├── structured_message_test.go
│ ├── write_structured_message.go
│ └── write_structured_message_test.go
└── write.go
├── client
├── client.go
├── client_http.go
├── client_observed.go
├── client_test.go
├── defaulters.go
├── defaulters_test.go
├── doc.go
├── http_receiver.go
├── http_receiver_test.go
├── invoker.go
├── observability.go
├── options.go
├── options_test.go
├── receiver.go
├── receiver_test.go
└── test
│ ├── mock_client.go
│ ├── mock_client_test.go
│ └── test.go
├── context
├── context.go
├── context_test.go
├── delegating.go
├── delegating_test.go
├── doc.go
├── logger.go
├── logger_test.go
├── retry.go
└── retry_test.go
├── event
├── content_type.go
├── content_type_test.go
├── data_content_encoding.go
├── data_content_encoding_test.go
├── datacodec
│ ├── codec.go
│ ├── codec_test.go
│ ├── doc.go
│ ├── json
│ │ ├── data.go
│ │ ├── data_test.go
│ │ └── doc.go
│ ├── text
│ │ ├── data.go
│ │ ├── data_test.go
│ │ └── doc.go
│ └── xml
│ │ ├── data.go
│ │ ├── data_test.go
│ │ └── doc.go
├── doc.go
├── event.go
├── event_data.go
├── event_data_test.go
├── event_interface.go
├── event_marshal.go
├── event_marshal_benchmark_test.go
├── event_marshal_roundtrip_test.go
├── event_marshal_test.go
├── event_reader.go
├── event_reader_writer_test.go
├── event_test.go
├── event_unmarshal.go
├── event_unmarshal_benchmark_test.go
├── event_unmarshal_test.go
├── event_validation.go
├── event_writer.go
├── eventcontext.go
├── eventcontext_test.go
├── eventcontext_v03.go
├── eventcontext_v03_reader.go
├── eventcontext_v03_test.go
├── eventcontext_v03_writer.go
├── eventcontext_v1.go
├── eventcontext_v1_reader.go
├── eventcontext_v1_test.go
├── eventcontext_v1_writer.go
├── extensions.go
└── extensions_test.go
├── extensions
├── dataref_extension.go
├── dataref_extension_test.go
├── distributed_tracing_extension.go
├── distributed_tracing_extension_test.go
└── doc.go
├── go.mod
├── go.sum
├── observability
├── doc.go
└── keys.go
├── protocol
├── doc.go
├── error.go
├── gochan
│ ├── doc.go
│ ├── protocol.go
│ ├── protocol_test.go
│ ├── receiver.go
│ ├── requester.go
│ ├── responder.go
│ └── sender.go
├── http
│ ├── abuse_protection.go
│ ├── context.go
│ ├── context_test.go
│ ├── doc.go
│ ├── headers.go
│ ├── headers_test.go
│ ├── message.go
│ ├── message_test.go
│ ├── options.go
│ ├── options_test.go
│ ├── protocol.go
│ ├── protocol_lifecycle.go
│ ├── protocol_rate.go
│ ├── protocol_retry.go
│ ├── protocol_retry_test.go
│ ├── protocol_test.go
│ ├── result.go
│ ├── result_test.go
│ ├── retries_result.go
│ ├── retries_result_test.go
│ ├── utility.go
│ ├── utility_test.go
│ ├── write_request.go
│ ├── write_responsewriter.go
│ └── write_responsewriter_test.go
├── inbound.go
├── lifecycle.go
├── outbound.go
├── result.go
├── result_test.go
└── test
│ ├── benchmark.go
│ ├── doc.go
│ ├── test.go
│ └── test_test.go
├── staticcheck.conf
├── test
├── doc.go
├── event_asserts.go
├── event_asserts_test.go
├── event_matchers.go
├── event_matchers_test.go
├── event_mocks.go
└── helpers.go
└── types
├── allocate.go
├── allocate_test.go
├── doc.go
├── timestamp.go
├── timestamp_test.go
├── uri.go
├── uri_test.go
├── uriref.go
├── uriref_test.go
├── value.go
└── value_test.go
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @cloudevents/sdk-go-maintainers
2 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "github-actions"
4 | directory: "/"
5 | schedule:
6 | interval: "daily"
--------------------------------------------------------------------------------
/.github/workflows/conformance.yaml:
--------------------------------------------------------------------------------
1 | name: Conformance
2 |
3 | on:
4 | push:
5 | branches: [ 'main', 'release-*' ]
6 | pull_request:
7 | branches: [ 'main', 'release-*' ]
8 |
9 | permissions:
10 | contents: read
11 |
12 | jobs:
13 |
14 | conformance:
15 | name: CloudEvents Conformance
16 | strategy:
17 | matrix:
18 | go-version: [1.23]
19 | platform: [ubuntu-latest]
20 |
21 | runs-on: ${{ matrix.platform }}
22 |
23 | steps:
24 | - name: Checkout code
25 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
26 |
27 | - name: Setup Go ${{ matrix.go-version }}
28 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
29 | with:
30 | go-version: ${{ matrix.go-version }}
31 | cache-dependency-path: v2/go.sum
32 | id: go
33 |
34 | - name: Update git submodule
35 | run: git submodule sync && git submodule update --init
36 |
37 | - name: Build
38 | run: ./hack/conformance-test.sh
39 |
40 |
--------------------------------------------------------------------------------
/.github/workflows/go-build.yaml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on:
4 | push:
5 | branches: [ 'main', 'release-*' ]
6 | pull_request:
7 | branches: [ 'main', 'release-*' ]
8 |
9 | permissions:
10 | contents: read
11 |
12 | jobs:
13 |
14 | build:
15 | name: Build
16 | strategy:
17 | matrix:
18 | go-version: [1.23]
19 | platform: [ubuntu-latest]
20 |
21 | runs-on: ${{ matrix.platform }}
22 |
23 | steps:
24 | - name: Checkout code
25 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
26 |
27 | - name: Setup Go ${{ matrix.go-version }}
28 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
29 | with:
30 | go-version: ${{ matrix.go-version }}
31 | cache-dependency-path: v2/go.sum
32 | id: go
33 |
34 | - name: Build
35 | run: ./hack/build-test.sh
36 |
37 |
--------------------------------------------------------------------------------
/.github/workflows/go-format.yaml:
--------------------------------------------------------------------------------
1 | name: Go Format
2 |
3 | on:
4 | push:
5 | branches: [ 'main', 'release-*' ]
6 | pull_request:
7 | branches: [ 'main', 'release-*' ]
8 |
9 | permissions:
10 | contents: read
11 |
12 | jobs:
13 |
14 | format:
15 | name: Format
16 | runs-on: ubuntu-latest
17 |
18 | steps:
19 | - name: Checkout code
20 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
21 |
22 | - name: Setup Go
23 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
24 | with:
25 | go-version: 1.23
26 | cache-dependency-path: v2/go.sum
27 | id: go
28 |
29 | - name: Go Format
30 | shell: bash
31 | run: |
32 | gofmt -s -w $(find -type f -name '*.go' -print)
33 |
34 | - name: Verify
35 | shell: bash
36 | run: |
37 | if [[ $(git diff-index --name-only HEAD --) ]]; then
38 | echo "Found diffs in:"
39 | git diff-index --name-only HEAD --
40 | echo "${{ github.repository }} is out of style. Please run go fmt."
41 | exit 1
42 | fi
43 | echo "${{ github.repository }} is formatted correctly."
44 |
--------------------------------------------------------------------------------
/.github/workflows/go-lint.yaml:
--------------------------------------------------------------------------------
1 | name: Code Style
2 |
3 | on:
4 | push:
5 | branches: [ 'main', 'release-*' ]
6 | pull_request:
7 | branches: [ 'main', 'release-*' ]
8 |
9 | permissions:
10 | contents: read
11 |
12 | jobs:
13 |
14 | lint:
15 | name: Lint
16 | runs-on: ubuntu-latest
17 |
18 | steps:
19 | - name: Checkout code
20 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
21 |
22 | - name: Setup Go
23 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
24 | with:
25 | go-version: 1.23
26 | cache-dependency-path: v2/go.sum
27 | id: go
28 |
29 | - id: golangci_configuration
30 | uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3.0.0
31 | with:
32 | files: .golangci.yaml
33 |
34 | - name: Go Lint on ./v2
35 | if: steps.golangci_configuration.outputs.files_exists == 'true'
36 | uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0
37 | with:
38 | version: v2.1.6
39 | working-directory: v2
40 |
--------------------------------------------------------------------------------
/.github/workflows/go-unit-test.yaml:
--------------------------------------------------------------------------------
1 | name: Unit Test
2 |
3 | on:
4 | push:
5 | branches: [ 'main', 'release-*' ]
6 | pull_request:
7 | branches: [ 'main', 'release-*' ]
8 |
9 | permissions:
10 | contents: read
11 |
12 | jobs:
13 |
14 | test:
15 | name: Unit Test
16 | strategy:
17 | matrix:
18 | go-version: [1.23]
19 | platform: [ubuntu-latest]
20 |
21 | runs-on: ${{ matrix.platform }}
22 |
23 | steps:
24 | - name: Checkout code
25 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
26 |
27 | - name: Setup Go ${{ matrix.go-version }}
28 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
29 | with:
30 | go-version: ${{ matrix.go-version }}
31 | cache-dependency-path: v2/go.sum
32 | id: go
33 |
34 | - name: Test
35 | run: ./hack/unit-test.sh
36 |
--------------------------------------------------------------------------------
/.github/workflows/inclusive.yaml:
--------------------------------------------------------------------------------
1 | name: Inclusive
2 |
3 | on:
4 | pull_request:
5 | branches: [ 'main', 'release-*' ]
6 |
7 | permissions:
8 | contents: read
9 |
10 | jobs:
11 |
12 | language:
13 | name: Language
14 | runs-on: ubuntu-latest
15 |
16 | steps:
17 |
18 | - name: Checkout code
19 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
20 |
21 | - name: Woke
22 | uses: get-woke/woke-action-reviewdog@d71fd0115146a01c3181439ce714e21a69d75e31 # v0
23 | with:
24 | github-token: ${{ secrets.GITHUB_TOKEN }}
25 | reporter: github-pr-review
--------------------------------------------------------------------------------
/.github/workflows/observability.yaml:
--------------------------------------------------------------------------------
1 | name: Observability
2 |
3 | on:
4 | push:
5 | branches: [ 'main', 'release-*' ]
6 | pull_request:
7 | branches: [ 'main', 'release-*' ]
8 |
9 | permissions:
10 | contents: read
11 |
12 | jobs:
13 |
14 | observability:
15 | name: CloudEvents Observability
16 | strategy:
17 | matrix:
18 | go-version: [1.23]
19 | platform: [ubuntu-latest]
20 |
21 | runs-on: ${{ matrix.platform }}
22 |
23 | steps:
24 | - name: Checkout code
25 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
26 |
27 | - name: Setup Go ${{ matrix.go-version }}
28 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
29 | with:
30 | go-version: ${{ matrix.go-version }}
31 | cache-dependency-path: v2/go.sum
32 | id: go
33 |
34 | - name: Update git submodule
35 | run: git submodule sync && git submodule update --init
36 |
37 | - name: Build
38 | run: ./hack/observability-test.sh
39 |
--------------------------------------------------------------------------------
/.github/workflows/update-dependencies.yml:
--------------------------------------------------------------------------------
1 | name: Update Dependencies
2 |
3 | on:
4 | schedule:
5 | # Runs every Monday at 3:00 AM UTC
6 | - cron: '0 3 * * 1'
7 | # Allow manual triggering
8 | workflow_dispatch:
9 |
10 | jobs:
11 | update-dependencies:
12 | permissions:
13 | contents: write
14 | pull-requests: write
15 | runs-on: ubuntu-latest
16 | steps:
17 | - name: Checkout code
18 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
19 |
20 | - name: Setup Go
21 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
22 | with:
23 | go-version: 1.23
24 | cache-dependency-path: v2/go.sum
25 |
26 | - name: Run update dependencies script
27 | run: |
28 | chmod +x ./hack/update-deps.sh
29 | ./hack/update-deps.sh
30 |
31 | - name: Create Pull Request
32 | uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e
33 | with:
34 | base: main
35 | commit-message: "chore: update dependencies"
36 | title: "chore: update dependencies"
37 | body: |
38 | This PR updates Go dependencies.
39 |
40 | This is an automated PR created by the weekly dependency update workflow.
41 | branch: automated-dependency-updates
42 | delete-branch: true
43 | labels: dependencies
44 | reviewers: sdk-go-maintainers
45 | signoff: true
46 | sign-commits: true
47 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Operating system temporary files
2 | .DS_Store
3 |
4 | # Editor/IDE specific settings
5 | .idea
6 | .vscode/
7 |
8 | # Temporary output of build tools
9 | bazel-*
10 |
11 | # Binaries for programs and plugins
12 | *.exe
13 | *.exe~
14 | *.dll
15 | *.so
16 | *.dylib
17 |
18 | # Test binary, build with `go test -c`
19 | *.test
20 |
21 | # Output of the go coverage tool
22 | *.out
23 | coverage.txt
24 |
25 | # Jekyll stuff
26 | _site/
27 | .sass-cache/
28 | .jekyll-cache/
29 | .jekyll-metadata
30 |
31 | # Others
32 | ## IDE-specific
33 | *.iml
34 | test/benchmark/e2e/http/results/
35 | tmp/
36 | test/coverage.tmp
37 |
38 | vendor/
39 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "conformance"]
2 | path = conformance
3 | url = https://github.com/cloudevents/conformance.git
4 | branch = master
5 |
--------------------------------------------------------------------------------
/.golangci.yaml:
--------------------------------------------------------------------------------
1 | version: "2"
2 | run:
3 | timeout: 5m
4 |
5 | build-tags:
6 | - conformance
7 |
8 | linters:
9 | enable:
10 | - unconvert
11 | - prealloc
12 | disable:
13 | - errcheck
14 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to CloudEvents sdk-go
2 |
3 | :+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
4 |
5 | We welcome contributions from the community! Please take some time to become
6 | acquainted with the process before submitting a pull request. There are just
7 | a few things to keep in mind.
8 |
9 | ## Pull Requests
10 |
11 | Typically a pull request should relate to an existing issue. If you have
12 | found a bug, want to add an improvement, or suggest an API change, please
13 | create an issue before proceeding with a pull request. For very minor changes
14 | such as typos in the documentation this isn't really necessary.
15 |
16 | For step by step help with managing your pull request, have a look at our
17 | [PR Guidelines](pr_guidelines.md) document.
18 |
19 | ### Sign your work
20 |
21 | Each PR must be signed. Be sure your `git` `user.name` and `user.email` are configured
22 | then use the `--signoff` flag for your commits.
23 |
24 | ```console
25 | git commit --signoff
26 | ```
27 |
28 | ### Style Guide
29 |
30 | Code style for this module is maintained using [`go fmt`](https://golang.org/cmd/go/#hdr-Gofmt__reformat__package_sources).
31 |
32 | ### Maintainers
33 |
34 | If you are a maintainer of this repository, [here](maintainers_guide.pr) is a brief
35 | guide with helpful tips.
36 |
--------------------------------------------------------------------------------
/MAINTAINERS.md:
--------------------------------------------------------------------------------
1 | # Maintainers
2 |
3 | Current active maintainers of this SDK:
4 |
5 | - [Michael Gasch](https://github.com/embano1)
6 | - [Lionel Villard](https://github.com/lionelvillard)
7 | - [Doug Davis](https://github.com/duglin)
8 | - [Sasha Tkachev](https://github.com/sasha-tkachev)
9 |
--------------------------------------------------------------------------------
/binding/format/protobuf/v2/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/binding/format/protobuf/v2
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | require (
8 | github.com/cloudevents/sdk-go/v2 v2.16.0
9 | github.com/stretchr/testify v1.10.0
10 | google.golang.org/protobuf v1.36.6
11 | )
12 |
13 | require (
14 | github.com/davecgh/go-spew v1.1.1 // indirect
15 | github.com/google/uuid v1.6.0 // indirect
16 | github.com/json-iterator/go v1.1.12 // indirect
17 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
18 | github.com/modern-go/reflect2 v1.0.2 // indirect
19 | github.com/pmezard/go-difflib v1.0.0 // indirect
20 | go.uber.org/multierr v1.11.0 // indirect
21 | go.uber.org/zap v1.27.0 // indirect
22 | gopkg.in/yaml.v3 v3.0.1 // indirect
23 | )
24 |
25 | replace github.com/cloudevents/sdk-go/v2 => ../../../../v2
26 |
--------------------------------------------------------------------------------
/binding/format/protobuf/v2/pb/gen.go:
--------------------------------------------------------------------------------
1 | package pb
2 |
3 | //go:generate protoc --go_out=. --go_opt=paths=source_relative cloudevent.proto
4 |
--------------------------------------------------------------------------------
/docs/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 | # Hello! This is where you manage which Jekyll version is used to run.
3 | # When you want to use a different version, change it below, save the
4 | # file and run `bundle install`. Run Jekyll with `bundle exec`, like so:
5 | #
6 | # bundle exec jekyll serve
7 | #
8 | # This will help ensure the proper Jekyll version is running.
9 | # Happy Jekylling!
10 |
11 | gem "jekyll", "~> 3.8.7"
12 | gem "github-pages", group: :jekyll_plugins
13 |
14 | gem "just-the-docs"
15 |
16 | # If you have any plugins, put them here!
17 | group :jekyll_plugins do
18 | gem "jekyll-feed", "~> 0.13"
19 | end
20 |
21 | # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem
22 | # and associated library.
23 | install_if -> { RUBY_PLATFORM =~ %r!mingw|mswin|java! } do
24 | gem "tzinfo", "~> 1.2"
25 | gem "tzinfo-data"
26 | end
27 |
28 | # Performance-booster for watching directories on Windows
29 | gem "wdm", "~> 0.1.1", :install_if => Gem.win_platform?
30 |
31 |
--------------------------------------------------------------------------------
/docs/_config.yml:
--------------------------------------------------------------------------------
1 | # To configure the environment locally to test the website, check out
2 | # https://help.github.com/en/github/working-with-github-pages/testing-your-github-pages-site-locally-with-jekyll
3 |
4 | title: Golang SDK for CloudEvents
5 | remote_theme: pmarsceill/just-the-docs
6 | plugins:
7 | - jemoji
8 |
9 | aux_links:
10 | "GitHub Repository":
11 | - "https://github.com/cloudevents/sdk-go"
12 | "CloudEvents home":
13 | - "https://cloudevents.io/"
14 |
--------------------------------------------------------------------------------
/docs/images/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: all
2 |
3 | all: $(patsubst %.dot,%.svg,$(wildcard *.dot))
4 |
5 | %.svg: %.dot
6 | dot -Tsvg $< -o $@
--------------------------------------------------------------------------------
/docs/images/forwarder.dot:
--------------------------------------------------------------------------------
1 | digraph {
2 | rankdir=LR;
3 |
4 | Forwarder[shape=box]
5 |
6 | downstream -> Forwarder;
7 |
8 | Forwarder -> upstream;
9 | }
--------------------------------------------------------------------------------
/docs/images/mutator.dot:
--------------------------------------------------------------------------------
1 | digraph {
2 | rankdir=LR;
3 |
4 | Mutator[shape=box]
5 |
6 | Mutator -> upstream[dir=both];
7 | }
--------------------------------------------------------------------------------
/docs/images/mutator.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
33 |
--------------------------------------------------------------------------------
/docs/images/receiver.dot:
--------------------------------------------------------------------------------
1 | digraph {
2 | rankdir=LR;
3 |
4 | Receiver[shape=box]
5 | downstream -> Receiver;
6 | }
--------------------------------------------------------------------------------
/docs/images/receiver.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
32 |
--------------------------------------------------------------------------------
/docs/images/sender.dot:
--------------------------------------------------------------------------------
1 | digraph {
2 | rankdir=LR;
3 |
4 | Sender[shape=box]
5 |
6 | Sender -> upstream;
7 | }
--------------------------------------------------------------------------------
/docs/images/sender.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
32 |
--------------------------------------------------------------------------------
/docs/images/stack.dot:
--------------------------------------------------------------------------------
1 | digraph {
2 | rankdir=LR;
3 |
4 | Client -> ProtocolBinding [label="[Event]"]
5 | ProtocolBinding -> ProtocolBindingImpl [label="[Event, Message]"]
6 | ProtocolBindingImpl -> Protocol [label="[Message]"]
7 | }
--------------------------------------------------------------------------------
/hack/boilerplate/add-boilerplate.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Copyright 2021 The CloudEvents Authors
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | USAGE=$(cat <.txt to all . files missing it in a directory.
8 |
9 | Usage: (from repository root)
10 | ./hack/boilerplate/add-boilerplate.sh
11 |
12 | Example: (from repository root)
13 | ./hack/boilerplate/add-boilerplate.sh go cmd
14 | EOF
15 | )
16 |
17 | set -e
18 |
19 | if [[ -z $1 || -z $2 ]]; then
20 | echo "${USAGE}"
21 | exit 1
22 | fi
23 |
24 | grep --recursive --files-without-match --extended-regexp --regexp="Copyright \d+ The CloudEvents Authors" $2 \
25 | | grep --regexp="\.$1\$" \
26 | | xargs -I {} sh -c \
27 | "cat hack/boilerplate/boilerplate.$1.txt {} > /tmp/boilerplate && mv /tmp/boilerplate {}"
28 |
--------------------------------------------------------------------------------
/hack/boilerplate/boilerplate.go.txt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 |
--------------------------------------------------------------------------------
/hack/boilerplate/boilerplate.sh.txt:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Copyright 2021 The CloudEvents Authors
4 | # SPDX-License-Identifier: Apache-2.0
5 |
--------------------------------------------------------------------------------
/hack/build-test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Copyright 2021 The CloudEvents Authors
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | set -o errexit
7 | set -o nounset
8 |
9 | for gomodule in $(find . | grep "go\.mod" | awk '{gsub(/\/go.mod/,""); print $0}' | grep -v "./test" | grep -v "./conformance")
10 | do
11 | echo
12 | echo --- Building $gomodule ---
13 | echo
14 | pushd $gomodule
15 |
16 | tags="$(grep -I -r '// +build' . | cut -f3 -d' ' | sort | uniq | grep -v '^!' | tr '\n' ' ')"
17 |
18 | echo "Building with tags: ${tags}"
19 | go test -vet=off -tags "${tags}" -run=^$ ./... | grep -v "no test" || true
20 |
21 | popd
22 | done
23 |
--------------------------------------------------------------------------------
/hack/conformance-test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Copyright 2021 The CloudEvents Authors
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | set -o errexit
7 | set -o nounset
8 | set -o pipefail
9 |
10 | # test/conformance only
11 | pushd ./test/conformance
12 |
13 | go test --tags=conformance -v -timeout 15s
14 |
15 | # Remove test only deps.
16 | go mod tidy
17 | popd
18 |
--------------------------------------------------------------------------------
/hack/go-mod-tidy.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Copyright 2022 The CloudEvents Authors
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | set -o errexit
7 | set -o nounset
8 | set -o pipefail
9 |
10 | for gomodule in $(find . | grep "go\.mod" | awk '{gsub(/\/go.mod/,""); print $0}' | grep -v "./conformance")
11 | do
12 | pushd $gomodule
13 | go mod tidy
14 | popd
15 | done
16 |
--------------------------------------------------------------------------------
/hack/integration-test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Copyright 2021 The CloudEvents Authors
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | set -o errexit
7 | set -o nounset
8 | set -o pipefail
9 |
10 | COVERAGE="`pwd`/coverage.txt"
11 |
12 | # ./test/integration only
13 | pushd ./test/integration
14 |
15 | # Run integration tests not in parallel
16 | # Prepare coverage file only if not exists
17 | if [ ! -f $COVERAGE ]; then
18 | touch ./coverage.tmp
19 | echo 'mode: atomic' > $COVERAGE
20 | fi
21 | COVERPKG=$(go list ./... | grep -v /vendor | tr "\n" ",")
22 | for gomodule in $(go list ./... | grep -v /cmd | grep -v /vendor)
23 | do
24 | go test -v -parallel 1 -timeout 10m -race -covermode=atomic -coverprofile=coverage.tmp -coverpkg "$COVERPKG" "$gomodule" 2>&1 | sed 's/ of statements in.*//; /warning: no packages being tested depend on matches for pattern /d'
25 | tail -n +2 coverage.tmp >> $COVERAGE
26 | done
27 | rm coverage.tmp
28 |
29 | # Remove test only deps.
30 | go mod tidy
31 |
32 | popd
33 |
--------------------------------------------------------------------------------
/hack/observability-test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Copyright 2021 The CloudEvents Authors
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | set -o errexit
7 | set -o nounset
8 | set -o pipefail
9 |
10 | COVERAGE="`pwd`/coverage.txt"
11 |
12 | # test/observability only
13 | pushd ./test/observability
14 |
15 | # Prepare coverage file only if not exists
16 | if [ ! -f $COVERAGE ]; then
17 | touch ./coverage.tmp
18 | echo 'mode: atomic' > $COVERAGE
19 | fi
20 | COVERPKG="github.com/cloudevents/sdk-go/observability/opentelemetry/v2/..."
21 | for gomodule in $(go list ./... | grep -v /cmd | grep -v /vendor)
22 | do
23 | go test -v -timeout 30s -race -covermode=atomic -coverprofile=coverage.tmp -coverpkg "$COVERPKG" "$gomodule" 2>&1 | sed 's/ of statements in.*//; /warning: no packages being tested depend on matches for pattern /d'
24 | tail -n +2 coverage.tmp >> $COVERAGE
25 | done
26 | rm coverage.tmp
27 |
28 | # Remove test only deps.
29 | go mod tidy
30 |
31 | popd
32 |
--------------------------------------------------------------------------------
/hack/run-integration-services.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Run the services needed by the integration test in our local docker install
4 |
5 | if [[ "$1" == "stop" ]]; then
6 | docker rm -f kafka nats amqp mqtt
7 | exit 0
8 | fi
9 |
10 | # Kafka
11 | docker run --name kafka -dti -e ADV_HOST=localhost -p 9091:9091 -p 9092:9092 \
12 | lensesio/fast-data-dev
13 |
14 | # NATS
15 | docker run --name nats -dti -p 4222:4222 nats-streaming:0.22.1
16 |
17 | # AMQP
18 | docker run --name amqp -dti -e QDROUTERD_CONFIG_OPTIONS='
19 | router {
20 | mode: standalone
21 | id: ZTg2NDQ0N2Q1YjU1OGE1N2NkNzY4NDFk
22 | workerThreads: 4
23 | }
24 | log {
25 | module: DEFAULT
26 | enable: trace+
27 | timestamp: true
28 | }
29 | listener {
30 | role: normal
31 | host: 0.0.0.0
32 | port: amqp
33 | saslMechanisms: ANONYMOUS
34 | }' -p 5672:5672 scholzj/qpid-dispatch
35 |
36 | # MQTT
37 | docker run --name mqtt -dti -p 1883:1883 eclipse-mosquitto:1.6
38 |
39 |
--------------------------------------------------------------------------------
/hack/unit-test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Copyright 2021 The CloudEvents Authors
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | set -o errexit
7 | set -o nounset
8 | set -o pipefail
9 |
10 | COVERAGE="`pwd`/coverage.txt"
11 | echo 'mode: atomic' > $COVERAGE
12 |
13 | for gomodule in $(find . | grep "go\.mod" | awk '{gsub(/\/go.mod/,""); print $0}' | grep -v "./test" | grep -v "./conformance")
14 | do
15 | echo
16 | echo --- Testing $gomodule ---
17 | echo
18 |
19 | pushd $gomodule
20 | touch ./coverage.tmp
21 | COVERPKG=$(go list ./... | grep -v /vendor | grep -v /test | tr "\n" ",")
22 |
23 | go test -v -timeout 30s -race -covermode=atomic -coverprofile=coverage.tmp -coverpkg "$COVERPKG" ./... 2>&1 | sed 's/ of statements in.*//; /warning: no packages being tested depend on matches for pattern /d'
24 | tail -n +2 coverage.tmp >> $COVERAGE
25 |
26 | rm coverage.tmp
27 | # Remove test only deps.
28 | go mod tidy
29 | popd
30 | done
31 |
--------------------------------------------------------------------------------
/hack/update-deps.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright 2022 The CloudEvents Authors
3 | # SPDX-License-Identifier: Apache-2.0
4 | # update-deps.sh - Updates Go dependencies in all directories with go.mod files
5 | #
6 | # This script:
7 | # 1. Finds all directories containing go.mod files
8 | # 2. Goes into each directory and runs go get -u to update dependencies
9 | # 3. Runs go mod tidy to clean up the go.mod and go.sum files
10 |
11 | set -euo pipefail
12 |
13 | echo "====================================="
14 | echo "Go Dependencies Update Script"
15 | echo "====================================="
16 |
17 | echo "Finding all directories with go.mod files..."
18 | DIRS=$(find . -name "go.mod" -exec dirname {} \;)
19 | if [ -z "$DIRS" ]; then
20 | echo "No go.mod files found!"
21 | exit 0
22 | fi
23 |
24 | DIR_COUNT=$(echo "$DIRS" | wc -l | tr -d ' ')
25 | echo "Found $DIR_COUNT directories with go.mod files"
26 | echo
27 |
28 | COUNTER=1
29 | for DIR in $DIRS; do
30 | echo "[$COUNTER/$DIR_COUNT] Processing $DIR"
31 |
32 | pushd "$DIR" >/dev/null
33 |
34 | echo " - Updating dependencies..."
35 | go get -u -t ./...
36 |
37 | echo " - Running go mod tidy..."
38 | go mod tidy
39 |
40 | popd >/dev/null
41 |
42 | echo " - Done"
43 | echo
44 |
45 | COUNTER=$((COUNTER + 1))
46 | done
47 |
48 | echo "All dependencies updated successfully!"
49 |
--------------------------------------------------------------------------------
/observability/opencensus/v2/client/client.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package client
7 |
8 | import (
9 | obshttp "github.com/cloudevents/sdk-go/observability/opencensus/v2/http"
10 | "github.com/cloudevents/sdk-go/v2/client"
11 | "github.com/cloudevents/sdk-go/v2/protocol/http"
12 | )
13 |
14 | func NewClientHTTP(topt []http.Option, copt []client.Option) (client.Client, error) {
15 | t, err := obshttp.NewObservedHTTP(topt...)
16 | if err != nil {
17 | return nil, err
18 | }
19 |
20 | copt = append(copt, client.WithTimeNow(), client.WithUUIDs(), client.WithObservabilityService(New()))
21 |
22 | c, err := client.New(t, copt...)
23 | if err != nil {
24 | return nil, err
25 | }
26 |
27 | return c, nil
28 | }
29 |
--------------------------------------------------------------------------------
/observability/opencensus/v2/client/trace_attributes.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package client
7 |
8 | import (
9 | "go.opencensus.io/trace"
10 |
11 | "github.com/cloudevents/sdk-go/v2/event"
12 | "github.com/cloudevents/sdk-go/v2/observability"
13 | )
14 |
15 | func EventTraceAttributes(e event.EventReader) []trace.Attribute {
16 | as := []trace.Attribute{
17 | trace.StringAttribute(observability.SpecversionAttr, e.SpecVersion()),
18 | trace.StringAttribute(observability.IdAttr, e.ID()),
19 | trace.StringAttribute(observability.TypeAttr, e.Type()),
20 | trace.StringAttribute(observability.SourceAttr, e.Source()),
21 | }
22 | if sub := e.Subject(); sub != "" {
23 | as = append(as, trace.StringAttribute(observability.SubjectAttr, sub))
24 | }
25 | if dct := e.DataContentType(); dct != "" {
26 | as = append(as, trace.StringAttribute(observability.DatacontenttypeAttr, dct))
27 | }
28 | return as
29 | }
30 |
--------------------------------------------------------------------------------
/observability/opencensus/v2/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/observability/opencensus/v2
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | require (
8 | github.com/cloudevents/sdk-go/v2 v2.16.0
9 | github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac
10 | github.com/stretchr/testify v1.10.0
11 | go.opencensus.io v0.24.0
12 | )
13 |
14 | require (
15 | github.com/davecgh/go-spew v1.1.1 // indirect
16 | github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
17 | github.com/google/uuid v1.6.0 // indirect
18 | github.com/json-iterator/go v1.1.12 // indirect
19 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
20 | github.com/modern-go/reflect2 v1.0.2 // indirect
21 | github.com/onsi/ginkgo v1.14.2 // indirect
22 | github.com/onsi/gomega v1.10.4 // indirect
23 | github.com/pmezard/go-difflib v1.0.0 // indirect
24 | go.uber.org/multierr v1.11.0 // indirect
25 | go.uber.org/zap v1.27.0 // indirect
26 | golang.org/x/net v0.38.0 // indirect
27 | gopkg.in/yaml.v3 v3.0.1 // indirect
28 | )
29 |
30 | replace github.com/cloudevents/sdk-go/v2 => ../../../v2
31 |
--------------------------------------------------------------------------------
/observability/opencensus/v2/http/http.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package http
7 |
8 | import (
9 | "net/http"
10 |
11 | "go.opencensus.io/plugin/ochttp"
12 | "go.opencensus.io/plugin/ochttp/propagation/tracecontext"
13 |
14 | cehttp "github.com/cloudevents/sdk-go/v2/protocol/http"
15 | )
16 |
17 | func roundtripperDecorator(roundTripper http.RoundTripper) http.RoundTripper {
18 | return &ochttp.Transport{
19 | Propagation: &tracecontext.HTTPFormat{},
20 | Base: roundTripper,
21 | FormatSpanName: formatSpanName,
22 | }
23 | }
24 |
25 | func formatSpanName(r *http.Request) string {
26 | return "cloudevents.http." + r.URL.Path
27 | }
28 |
29 | func tracecontextMiddleware(h http.Handler) http.Handler {
30 | return &ochttp.Handler{
31 | Propagation: &tracecontext.HTTPFormat{},
32 | Handler: h,
33 | FormatSpanName: formatSpanName,
34 | }
35 | }
36 |
37 | // NewObservedHTTP creates an HTTP protocol with trace propagating middleware.
38 | func NewObservedHTTP(opts ...cehttp.Option) (*cehttp.Protocol, error) {
39 | return cehttp.New(append(
40 | []cehttp.Option{
41 | cehttp.WithRoundTripperDecorator(roundtripperDecorator),
42 | cehttp.WithMiddleware(tracecontextMiddleware),
43 | },
44 | opts...,
45 | )...)
46 | }
47 |
--------------------------------------------------------------------------------
/observability/opentelemetry/v2/client/client.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package client
7 |
8 | import (
9 | obshttp "github.com/cloudevents/sdk-go/observability/opentelemetry/v2/http"
10 | "github.com/cloudevents/sdk-go/v2/client"
11 | cehttp "github.com/cloudevents/sdk-go/v2/protocol/http"
12 | )
13 |
14 | // NewClientHTTP produces a new client instrumented with OpenTelemetry.
15 | func NewClientHTTP(topt []cehttp.Option, copt []client.Option, obsOpts ...OTelObservabilityServiceOption) (client.Client, error) {
16 | t, err := obshttp.NewObservedHTTP(topt...)
17 | if err != nil {
18 | return nil, err
19 | }
20 |
21 | copt = append(
22 | copt,
23 | client.WithTimeNow(),
24 | client.WithUUIDs(),
25 | client.WithObservabilityService(NewOTelObservabilityService(obsOpts...)),
26 | )
27 |
28 | c, err := client.New(t, copt...)
29 | if err != nil {
30 | return nil, err
31 | }
32 |
33 | return c, nil
34 | }
35 |
--------------------------------------------------------------------------------
/observability/opentelemetry/v2/client/otel_options.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package client
7 |
8 | import (
9 | "go.opentelemetry.io/otel/attribute"
10 |
11 | cloudevents "github.com/cloudevents/sdk-go/v2"
12 | "github.com/cloudevents/sdk-go/v2/observability"
13 | )
14 |
15 | const (
16 | // The value for the `otel.library.name` span attribute
17 | instrumentationName = "github.com/cloudevents/sdk-go/observability/opentelemetry/v2"
18 | )
19 |
20 | type OTelObservabilityServiceOption func(*OTelObservabilityService)
21 |
22 | // WithSpanAttributesGetter appends the returned attributes from the function to the span.
23 | func WithSpanAttributesGetter(attrGetter func(cloudevents.Event) []attribute.KeyValue) OTelObservabilityServiceOption {
24 | return func(os *OTelObservabilityService) {
25 | if attrGetter != nil {
26 | os.spanAttributesGetter = attrGetter
27 | }
28 | }
29 | }
30 |
31 | // WithSpanNameFormatter replaces the default span name with the string returned from the function
32 | func WithSpanNameFormatter(nameFormatter func(cloudevents.Event) string) OTelObservabilityServiceOption {
33 | return func(os *OTelObservabilityService) {
34 | if nameFormatter != nil {
35 | os.spanNameFormatter = nameFormatter
36 | }
37 | }
38 | }
39 |
40 | var defaultSpanNameFormatter func(cloudevents.Event) string = func(e cloudevents.Event) string {
41 | return observability.ClientSpanName + "." + e.Context.GetType()
42 | }
43 |
--------------------------------------------------------------------------------
/observability/opentelemetry/v2/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/observability/opentelemetry/v2
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | require (
8 | github.com/cloudevents/sdk-go/v2 v2.16.0
9 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0
10 | go.opentelemetry.io/otel v1.36.0
11 | go.opentelemetry.io/otel/trace v1.36.0
12 | )
13 |
14 | require (
15 | github.com/felixge/httpsnoop v1.0.4 // indirect
16 | github.com/go-logr/logr v1.4.3 // indirect
17 | github.com/go-logr/stdr v1.2.2 // indirect
18 | github.com/google/uuid v1.6.0 // indirect
19 | github.com/json-iterator/go v1.1.12 // indirect
20 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
21 | github.com/modern-go/reflect2 v1.0.2 // indirect
22 | go.opentelemetry.io/auto/sdk v1.1.0 // indirect
23 | go.opentelemetry.io/otel/metric v1.36.0 // indirect
24 | go.uber.org/multierr v1.11.0 // indirect
25 | go.uber.org/zap v1.27.0 // indirect
26 | )
27 |
28 | replace github.com/cloudevents/sdk-go/v2 => ../../../v2
29 |
--------------------------------------------------------------------------------
/observability/opentelemetry/v2/http/http.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package http
7 |
8 | import (
9 | "net/http"
10 |
11 | "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
12 |
13 | cehttp "github.com/cloudevents/sdk-go/v2/protocol/http"
14 | )
15 |
16 | // NewObservedHTTP creates an HTTP protocol with OTel trace propagating middleware.
17 | func NewObservedHTTP(opts ...cehttp.Option) (*cehttp.Protocol, error) {
18 | // appends the OpenTelemetry Http transport + Middleware wrapper
19 | // to properly trace outgoing and incoming requests from the client using this protocol
20 | return cehttp.New(append(
21 | []cehttp.Option{
22 | cehttp.WithRoundTripper(otelhttp.NewTransport(http.DefaultTransport)),
23 | cehttp.WithMiddleware(func(next http.Handler) http.Handler {
24 | return otelhttp.NewHandler(next, "cloudevents.http.receiver")
25 | }),
26 | },
27 | opts...,
28 | )...)
29 | }
30 |
--------------------------------------------------------------------------------
/protocol/amqp/v2/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package amqp implements an AMQP binding using pack.ag/amqp module
8 | */
9 | package amqp
10 |
--------------------------------------------------------------------------------
/protocol/amqp/v2/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/protocol/amqp/v2
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | replace github.com/Azure/go-amqp => github.com/Azure/go-amqp v0.17.0
8 |
9 | replace github.com/cloudevents/sdk-go/v2 => ../../../v2
10 |
11 | require (
12 | github.com/Azure/go-amqp v1.4.0
13 | github.com/cloudevents/sdk-go/v2 v2.16.0
14 | github.com/stretchr/testify v1.10.0
15 | )
16 |
17 | require (
18 | github.com/davecgh/go-spew v1.1.1 // indirect
19 | github.com/google/go-cmp v0.7.0 // indirect
20 | github.com/json-iterator/go v1.1.12 // indirect
21 | github.com/kr/text v0.2.0 // indirect
22 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
23 | github.com/modern-go/reflect2 v1.0.2 // indirect
24 | github.com/pmezard/go-difflib v1.0.0 // indirect
25 | gopkg.in/yaml.v3 v3.0.1 // indirect
26 | )
27 |
--------------------------------------------------------------------------------
/protocol/amqp/v2/options.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package amqp
7 |
8 | import (
9 | "github.com/Azure/go-amqp"
10 | )
11 |
12 | // Option is the function signature required to be considered an amqp.Option.
13 | type Option func(*Protocol) error
14 |
15 | // WithConnOpt sets a connection option for amqp
16 | func WithConnOpt(opt amqp.ConnOption) Option {
17 | return func(t *Protocol) error {
18 | t.connOpts = append(t.connOpts, opt)
19 | return nil
20 | }
21 | }
22 |
23 | // WithConnSASLPlain sets SASLPlain connection option for amqp
24 | func WithConnSASLPlain(username, password string) Option {
25 | return WithConnOpt(amqp.ConnSASLPlain(username, password))
26 | }
27 |
28 | // WithSessionOpt sets a session option for amqp
29 | func WithSessionOpt(opt amqp.SessionOption) Option {
30 | return func(t *Protocol) error {
31 | t.sessionOpts = append(t.sessionOpts, opt)
32 | return nil
33 | }
34 | }
35 |
36 | // WithSenderLinkOption sets a link option for amqp
37 | func WithSenderLinkOption(opt amqp.LinkOption) Option {
38 | return func(t *Protocol) error {
39 | t.senderLinkOpts = append(t.senderLinkOpts, opt)
40 | return nil
41 | }
42 | }
43 |
44 | // WithReceiverLinkOption sets a link option for amqp
45 | func WithReceiverLinkOption(opt amqp.LinkOption) Option {
46 | return func(t *Protocol) error {
47 | t.receiverLinkOpts = append(t.receiverLinkOpts, opt)
48 | return nil
49 | }
50 | }
51 |
52 | // SenderOptionFunc is the type of amqp.Sender options
53 | type SenderOptionFunc func(sender *sender)
54 |
--------------------------------------------------------------------------------
/protocol/amqp/v2/receiver.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package amqp
7 |
8 | import (
9 | "context"
10 | "io"
11 | "strings"
12 |
13 | "github.com/Azure/go-amqp"
14 |
15 | "github.com/cloudevents/sdk-go/v2/binding"
16 | "github.com/cloudevents/sdk-go/v2/protocol"
17 | )
18 |
19 | const serverDown = "session ended by server"
20 |
21 | // receiver wraps an amqp.Receiver as a binding.Receiver
22 | type receiver struct{ amqp *amqp.Receiver }
23 |
24 | func (r *receiver) Receive(ctx context.Context) (binding.Message, error) {
25 | m, err := r.amqp.Receive(ctx)
26 | if err != nil {
27 | if err == ctx.Err() {
28 | return nil, io.EOF
29 | }
30 | // handle case when server goes down
31 | if strings.HasPrefix(err.Error(), serverDown) {
32 | return nil, io.EOF
33 | }
34 | return nil, err
35 | }
36 |
37 | return NewMessage(m, r.amqp), nil
38 | }
39 |
40 | // NewReceiver create a new Receiver which wraps an amqp.Receiver in a binding.Receiver
41 | func NewReceiver(amqp *amqp.Receiver) protocol.Receiver {
42 | return &receiver{amqp: amqp}
43 | }
44 |
--------------------------------------------------------------------------------
/protocol/amqp/v2/sender.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package amqp
7 |
8 | import (
9 | "context"
10 |
11 | "github.com/Azure/go-amqp"
12 |
13 | "github.com/cloudevents/sdk-go/v2/binding"
14 | "github.com/cloudevents/sdk-go/v2/protocol"
15 | )
16 |
17 | // sender wraps an amqp.Sender as a binding.Sender
18 | type sender struct {
19 | amqp *amqp.Sender
20 | }
21 |
22 | func (s *sender) Send(ctx context.Context, in binding.Message, transformers ...binding.Transformer) error {
23 | var err error
24 | defer func() { _ = in.Finish(err) }()
25 | if m, ok := in.(*Message); ok { // Already an AMQP message.
26 | err = s.amqp.Send(ctx, m.AMQP)
27 | return err
28 | }
29 |
30 | var amqpMessage amqp.Message
31 | err = WriteMessage(ctx, in, &amqpMessage, transformers...)
32 | if err != nil {
33 | return err
34 | }
35 |
36 | err = s.amqp.Send(ctx, &amqpMessage)
37 | return err
38 | }
39 |
40 | // NewSender creates a new Sender which wraps an amqp.Sender in a binding.Sender
41 | func NewSender(amqpSender *amqp.Sender, options ...SenderOptionFunc) protocol.Sender {
42 | s := &sender{amqp: amqpSender}
43 | for _, o := range options {
44 | o(s)
45 | }
46 | return s
47 | }
48 |
--------------------------------------------------------------------------------
/protocol/amqp/v2/types.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package amqp
7 |
8 | import "github.com/cloudevents/sdk-go/v2/types"
9 |
10 | func safeAMQPPropertiesUnwrap(val interface{}) (interface{}, error) {
11 | v, err := types.Validate(val)
12 | if err != nil {
13 | return nil, err
14 | }
15 | switch t := v.(type) {
16 | case types.URI: // Use string form of URLs.
17 | v = t.String()
18 | case types.URIRef: // Use string form of URLs.
19 | v = t.String()
20 | case types.Timestamp: // Use string form of URLs.
21 | v = t.Time
22 | case int32: // Use AMQP long for Integer as per CE spec.
23 | v = int64(t)
24 | }
25 |
26 | return v, nil
27 | }
28 |
--------------------------------------------------------------------------------
/protocol/kafka_confluent/v2/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/protocol/kafka_confluent/v2
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | replace github.com/cloudevents/sdk-go/v2 => ../../../v2
8 |
9 | require (
10 | github.com/cloudevents/sdk-go/v2 v2.16.0
11 | github.com/confluentinc/confluent-kafka-go/v2 v2.10.0
12 | github.com/stretchr/testify v1.10.0
13 | )
14 |
15 | require (
16 | github.com/davecgh/go-spew v1.1.1 // indirect
17 | github.com/google/go-cmp v0.7.0 // indirect
18 | github.com/google/uuid v1.6.0 // indirect
19 | github.com/json-iterator/go v1.1.12 // indirect
20 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
21 | github.com/modern-go/reflect2 v1.0.2 // indirect
22 | github.com/pmezard/go-difflib v1.0.0 // indirect
23 | go.uber.org/multierr v1.11.0 // indirect
24 | go.uber.org/zap v1.27.0 // indirect
25 | gopkg.in/yaml.v3 v3.0.1 // indirect
26 | )
27 |
--------------------------------------------------------------------------------
/protocol/kafka_sarama/v2/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package kafka_sarama implements a Kafka binding using github.com/IBM/sarama module
8 | */
9 | package kafka_sarama
10 |
--------------------------------------------------------------------------------
/protocol/kafka_sarama/v2/message_benchmark_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package kafka_sarama_test
7 |
8 | import (
9 | "context"
10 | "testing"
11 |
12 | "github.com/cloudevents/sdk-go/protocol/kafka_sarama/v2"
13 | "github.com/cloudevents/sdk-go/v2/binding"
14 | "github.com/cloudevents/sdk-go/v2/event"
15 | )
16 |
17 | // Avoid DCE
18 | var M binding.Message
19 | var Event *event.Event
20 | var Err error
21 |
22 | func BenchmarkNewStructuredMessage(b *testing.B) {
23 | for i := 0; i < b.N; i++ {
24 | M = kafka_sarama.NewMessageFromConsumerMessage(structuredConsumerMessage)
25 | }
26 | }
27 |
28 | func BenchmarkNewBinaryMessage(b *testing.B) {
29 | for i := 0; i < b.N; i++ {
30 | M = kafka_sarama.NewMessageFromConsumerMessage(binaryConsumerMessage)
31 | }
32 | }
33 |
34 | func BenchmarkNewStructuredMessageToEvent(b *testing.B) {
35 | for i := 0; i < b.N; i++ {
36 | M = kafka_sarama.NewMessageFromConsumerMessage(structuredConsumerMessage)
37 | Event, Err = binding.ToEvent(context.TODO(), M)
38 | }
39 | }
40 |
41 | func BenchmarkNewBinaryMessageToEvent(b *testing.B) {
42 | for i := 0; i < b.N; i++ {
43 | M = kafka_sarama.NewMessageFromConsumerMessage(binaryConsumerMessage)
44 | Event, Err = binding.ToEvent(context.TODO(), M)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/protocol/kafka_sarama/v2/option.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package kafka_sarama
7 |
8 | import (
9 | "context"
10 | )
11 |
12 | // SenderOptionFunc is the type of kafka_sarama.Sender options
13 | type SenderOptionFunc func(sender *Sender)
14 |
15 | // ProtocolOptionFunc is the type of kafka_sarama.Protocol options
16 | type ProtocolOptionFunc func(protocol *Protocol)
17 |
18 | func WithReceiverGroupId(groupId string) ProtocolOptionFunc {
19 | return func(protocol *Protocol) {
20 | protocol.receiverGroupId = groupId
21 | }
22 | }
23 |
24 | func WithSenderContextDecorators(decorator func(context.Context) context.Context) ProtocolOptionFunc {
25 | return func(protocol *Protocol) {
26 | protocol.SenderContextDecorators = append(protocol.SenderContextDecorators, decorator)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/protocol/mqtt_paho/v2/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/protocol/mqtt_paho/v2
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | replace github.com/cloudevents/sdk-go/v2 => ../../../v2
8 |
9 | require (
10 | github.com/cloudevents/sdk-go/v2 v2.16.0
11 | github.com/eclipse/paho.golang v0.22.0
12 | github.com/stretchr/testify v1.10.0
13 | )
14 |
15 | require (
16 | github.com/davecgh/go-spew v1.1.1 // indirect
17 | github.com/google/go-cmp v0.7.0 // indirect
18 | github.com/json-iterator/go v1.1.12 // indirect
19 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
20 | github.com/modern-go/reflect2 v1.0.2 // indirect
21 | github.com/pmezard/go-difflib v1.0.0 // indirect
22 | go.uber.org/multierr v1.11.0 // indirect
23 | go.uber.org/zap v1.27.0 // indirect
24 | gopkg.in/yaml.v3 v3.0.1 // indirect
25 | )
26 |
--------------------------------------------------------------------------------
/protocol/mqtt_paho/v2/option.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2023 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package mqtt_paho
7 |
8 | import (
9 | "fmt"
10 |
11 | "github.com/eclipse/paho.golang/paho"
12 | )
13 |
14 | // Option is the function signature required to be considered an mqtt_paho.Option.
15 | type Option func(*Protocol) error
16 |
17 | // WithConnect sets the paho.Connect configuration for the client. This option is not required.
18 | func WithConnect(connOpt *paho.Connect) Option {
19 | return func(p *Protocol) error {
20 | if connOpt == nil {
21 | return fmt.Errorf("the paho.Connect option must not be nil")
22 | }
23 | p.connOption = connOpt
24 | return nil
25 | }
26 | }
27 |
28 | // WithPublish sets the paho.Publish configuration for the client. This option is required if you want to send messages.
29 | func WithPublish(publishOpt *paho.Publish) Option {
30 | return func(p *Protocol) error {
31 | if publishOpt == nil {
32 | return fmt.Errorf("the paho.Publish option must not be nil")
33 | }
34 | p.publishOption = publishOpt
35 | return nil
36 | }
37 | }
38 |
39 | // WithSubscribe sets the paho.Subscribe configuration for the client. This option is required if you want to receive messages.
40 | func WithSubscribe(subscribeOpt *paho.Subscribe) Option {
41 | return func(p *Protocol) error {
42 | if subscribeOpt == nil {
43 | return fmt.Errorf("the paho.Subscribe option must not be nil")
44 | }
45 | p.subscribeOption = subscribeOpt
46 | return nil
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/protocol/nats/v2/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package nats implements the CloudEvent transport implementation using NATS.
8 | */
9 | package nats
10 |
--------------------------------------------------------------------------------
/protocol/nats/v2/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/protocol/nats/v2
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | replace github.com/cloudevents/sdk-go/v2 => ../../../v2
8 |
9 | require (
10 | github.com/cloudevents/sdk-go/v2 v2.16.0
11 | github.com/nats-io/nats.go v1.42.0
12 | )
13 |
14 | require (
15 | github.com/json-iterator/go v1.1.12 // indirect
16 | github.com/klauspost/compress v1.18.0 // indirect
17 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
18 | github.com/modern-go/reflect2 v1.0.2 // indirect
19 | github.com/nats-io/nkeys v0.4.11 // indirect
20 | github.com/nats-io/nuid v1.0.1 // indirect
21 | golang.org/x/crypto v0.38.0 // indirect
22 | golang.org/x/sys v0.33.0 // indirect
23 | )
24 |
--------------------------------------------------------------------------------
/protocol/nats/v2/message.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package nats
7 |
8 | import (
9 | "bytes"
10 | "context"
11 |
12 | "github.com/cloudevents/sdk-go/v2/binding"
13 | "github.com/cloudevents/sdk-go/v2/binding/format"
14 | "github.com/nats-io/nats.go"
15 | )
16 |
17 | // Message implements binding.Message by wrapping an *nats.Msg.
18 | // This message *can* be read several times safely
19 | type Message struct {
20 | Msg *nats.Msg
21 | encoding binding.Encoding
22 | }
23 |
24 | // NewMessage wraps an *nats.Msg in a binding.Message.
25 | // The returned message *can* be read several times safely
26 | func NewMessage(msg *nats.Msg) *Message {
27 | return &Message{Msg: msg, encoding: binding.EncodingStructured}
28 | }
29 |
30 | var _ binding.Message = (*Message)(nil)
31 |
32 | func (m *Message) ReadEncoding() binding.Encoding {
33 | return m.encoding
34 | }
35 |
36 | func (m *Message) ReadStructured(ctx context.Context, encoder binding.StructuredWriter) error {
37 | return encoder.SetStructuredEvent(ctx, format.JSON, bytes.NewReader(m.Msg.Data))
38 | }
39 |
40 | func (m *Message) ReadBinary(ctx context.Context, encoder binding.BinaryWriter) error {
41 | return binding.ErrNotBinary
42 | }
43 |
44 | func (m *Message) Finish(err error) error {
45 | return nil
46 | }
47 |
--------------------------------------------------------------------------------
/protocol/nats/v2/options.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package nats
7 |
8 | import (
9 | "errors"
10 |
11 | "github.com/nats-io/nats.go"
12 | )
13 |
14 | var ErrInvalidQueueName = errors.New("invalid queue name for QueueSubscriber")
15 |
16 | // NatsOptions is a helper function to group a variadic nats.ProtocolOption into
17 | // []nats.Option that can be used by either Sender, Consumer or Protocol
18 | func NatsOptions(opts ...nats.Option) []nats.Option {
19 | return opts
20 | }
21 |
22 | // ProtocolOption is the function signature required to be considered an nats.ProtocolOption.
23 | type ProtocolOption func(*Protocol) error
24 |
25 | func WithConsumerOptions(opts ...ConsumerOption) ProtocolOption {
26 | return func(p *Protocol) error {
27 | p.consumerOptions = opts
28 | return nil
29 | }
30 | }
31 |
32 | func WithSenderOptions(opts ...SenderOption) ProtocolOption {
33 | return func(p *Protocol) error {
34 | p.senderOptions = opts
35 | return nil
36 | }
37 | }
38 |
39 | type SenderOption func(*Sender) error
40 |
41 | type ConsumerOption func(*Consumer) error
42 |
43 | // WithQueueSubscriber configures the Consumer to join a queue group when subscribing
44 | func WithQueueSubscriber(queue string) ConsumerOption {
45 | return func(c *Consumer) error {
46 | if queue == "" {
47 | return ErrInvalidQueueName
48 | }
49 | c.Subscriber = &QueueSubscriber{Queue: queue}
50 | return nil
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/protocol/nats/v2/options_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package nats
7 |
8 | import (
9 | "reflect"
10 | "testing"
11 | )
12 |
13 | func TestWithQueueSubscriber(t *testing.T) {
14 | type args struct {
15 | consumer *Consumer
16 | queue string
17 | }
18 | type wants struct {
19 | err error
20 | consumer *Consumer
21 | }
22 | tests := []struct {
23 | name string
24 | args args
25 | wants wants
26 | }{
27 | {
28 | name: "valid queue",
29 | args: args{
30 | consumer: &Consumer{},
31 | queue: "my-queue",
32 | },
33 | wants: wants{
34 | err: nil,
35 | consumer: &Consumer{
36 | Subscriber: &QueueSubscriber{Queue: "my-queue"},
37 | },
38 | },
39 | },
40 | {
41 | name: "invalid queue",
42 | args: args{
43 | consumer: &Consumer{},
44 | queue: "",
45 | },
46 | wants: wants{
47 | err: ErrInvalidQueueName,
48 | consumer: &Consumer{},
49 | },
50 | },
51 | }
52 | for _, tt := range tests {
53 | t.Run(tt.name, func(t *testing.T) {
54 | gotErr := tt.args.consumer.applyOptions(WithQueueSubscriber(tt.args.queue))
55 | if gotErr != tt.wants.err {
56 | t.Errorf("applyOptions(WithQueueSubscriber()) = %v, want %v", gotErr, tt.wants.err)
57 | }
58 |
59 | if !reflect.DeepEqual(tt.args.consumer, tt.wants.consumer) {
60 | t.Errorf("p = %v, want %v", tt.args.consumer, tt.wants.consumer)
61 | }
62 | })
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/protocol/nats/v2/subscriber.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package nats
7 |
8 | import (
9 | "github.com/nats-io/nats.go"
10 | )
11 |
12 | // The Subscriber interface allows us to configure how the subscription is created
13 | type Subscriber interface {
14 | Subscribe(conn *nats.Conn, subject string, cb nats.MsgHandler) (*nats.Subscription, error)
15 | }
16 |
17 | // RegularSubscriber creates regular subscriptions
18 | type RegularSubscriber struct {
19 | }
20 |
21 | // Subscribe implements Subscriber.Subscribe
22 | func (s *RegularSubscriber) Subscribe(conn *nats.Conn, subject string, cb nats.MsgHandler) (*nats.Subscription, error) {
23 | return conn.Subscribe(subject, cb)
24 | }
25 |
26 | var _ Subscriber = (*RegularSubscriber)(nil)
27 |
28 | // QueueSubscriber creates queue subscriptions
29 | type QueueSubscriber struct {
30 | Queue string
31 | }
32 |
33 | // Subscribe implements Subscriber.Subscribe
34 | func (s *QueueSubscriber) Subscribe(conn *nats.Conn, subject string, cb nats.MsgHandler) (*nats.Subscription, error) {
35 | return conn.QueueSubscribe(subject, s.Queue, cb)
36 | }
37 |
38 | var _ Subscriber = (*QueueSubscriber)(nil)
39 |
--------------------------------------------------------------------------------
/protocol/nats/v2/write_message.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package nats
7 |
8 | import (
9 | "context"
10 | "github.com/cloudevents/sdk-go/v2/binding"
11 | "github.com/cloudevents/sdk-go/v2/binding/format"
12 | "io"
13 | )
14 |
15 | // WriteMsg fills the provided writer with the bindings.Message m.
16 | // Using context you can tweak the encoding processing (more details on binding.Write documentation).
17 | func WriteMsg(ctx context.Context, m binding.Message, writer io.ReaderFrom, transformers ...binding.Transformer) error {
18 | structuredWriter := &natsMessageWriter{writer}
19 |
20 | _, err := binding.Write(
21 | ctx,
22 | m,
23 | structuredWriter,
24 | nil,
25 | transformers...,
26 | )
27 | return err
28 | }
29 |
30 | type natsMessageWriter struct {
31 | io.ReaderFrom
32 | }
33 |
34 | func (w *natsMessageWriter) SetStructuredEvent(_ context.Context, _ format.Format, event io.Reader) error {
35 | if _, err := w.ReadFrom(event); err != nil {
36 | return err
37 | }
38 |
39 | return nil
40 | }
41 |
42 | var _ binding.StructuredWriter = (*natsMessageWriter)(nil) // Test it conforms to the interface
43 |
--------------------------------------------------------------------------------
/protocol/nats_jetstream/v2/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package nats_jetstream implements the CloudEvent transport implementation using NATS JetStream.
8 | */
9 | package nats_jetstream
10 |
--------------------------------------------------------------------------------
/protocol/nats_jetstream/v2/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/protocol/nats_jetstream/v2
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | replace github.com/cloudevents/sdk-go/v2 => ../../../v2
8 |
9 | require (
10 | github.com/cloudevents/sdk-go/v2 v2.16.0
11 | github.com/nats-io/nats.go v1.42.0
12 | )
13 |
14 | require (
15 | github.com/davecgh/go-spew v1.1.1 // indirect
16 | github.com/google/go-cmp v0.7.0 // indirect
17 | github.com/json-iterator/go v1.1.12 // indirect
18 | github.com/klauspost/compress v1.18.0 // indirect
19 | github.com/kr/text v0.2.0 // indirect
20 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
21 | github.com/modern-go/reflect2 v1.0.2 // indirect
22 | github.com/nats-io/nkeys v0.4.11 // indirect
23 | github.com/nats-io/nuid v1.0.1 // indirect
24 | github.com/pmezard/go-difflib v1.0.0 // indirect
25 | github.com/stretchr/testify v1.10.0 // indirect
26 | golang.org/x/crypto v0.38.0 // indirect
27 | golang.org/x/sys v0.33.0 // indirect
28 | gopkg.in/yaml.v3 v3.0.1 // indirect
29 | )
30 |
--------------------------------------------------------------------------------
/protocol/nats_jetstream/v2/options.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package nats_jetstream
7 |
8 | import (
9 | "errors"
10 |
11 | "github.com/nats-io/nats.go"
12 | )
13 |
14 | var ErrInvalidQueueName = errors.New("invalid queue name for QueueSubscriber")
15 |
16 | // NatsOptions is a helper function to group a variadic nats.ProtocolOption into
17 | // []nats.Option that can be used by either Sender, Consumer or Protocol
18 | func NatsOptions(opts ...nats.Option) []nats.Option {
19 | return opts
20 | }
21 |
22 | // ProtocolOption is the function signature required to be considered an nats.ProtocolOption.
23 | type ProtocolOption func(*Protocol) error
24 |
25 | func WithConsumerOptions(opts ...ConsumerOption) ProtocolOption {
26 | return func(p *Protocol) error {
27 | p.consumerOptions = opts
28 | return nil
29 | }
30 | }
31 |
32 | func WithSenderOptions(opts ...SenderOption) ProtocolOption {
33 | return func(p *Protocol) error {
34 | p.senderOptions = opts
35 | return nil
36 | }
37 | }
38 |
39 | type SenderOption func(*Sender) error
40 |
41 | type ConsumerOption func(*Consumer) error
42 |
43 | // WithQueueSubscriber configures the Consumer to join a queue group when subscribing
44 | func WithQueueSubscriber(queue string) ConsumerOption {
45 | return func(c *Consumer) error {
46 | if queue == "" {
47 | return ErrInvalidQueueName
48 | }
49 | c.Subscriber = &QueueSubscriber{Queue: queue}
50 | return nil
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/protocol/nats_jetstream/v2/options_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package nats_jetstream
7 |
8 | import (
9 | "reflect"
10 | "testing"
11 | )
12 |
13 | func TestWithQueueSubscriber(t *testing.T) {
14 | type args struct {
15 | consumer *Consumer
16 | queue string
17 | }
18 | type wants struct {
19 | err error
20 | consumer *Consumer
21 | }
22 | tests := []struct {
23 | name string
24 | args args
25 | wants wants
26 | }{
27 | {
28 | name: "valid queue",
29 | args: args{
30 | consumer: &Consumer{},
31 | queue: "my-queue",
32 | },
33 | wants: wants{
34 | err: nil,
35 | consumer: &Consumer{
36 | Subscriber: &QueueSubscriber{Queue: "my-queue"},
37 | },
38 | },
39 | },
40 | {
41 | name: "invalid queue",
42 | args: args{
43 | consumer: &Consumer{},
44 | queue: "",
45 | },
46 | wants: wants{
47 | err: ErrInvalidQueueName,
48 | consumer: &Consumer{},
49 | },
50 | },
51 | }
52 | for _, tt := range tests {
53 | t.Run(tt.name, func(t *testing.T) {
54 | gotErr := tt.args.consumer.applyOptions(WithQueueSubscriber(tt.args.queue))
55 | if gotErr != tt.wants.err {
56 | t.Errorf("applyOptions(WithQueueSubscriber()) = %v, want %v", gotErr, tt.wants.err)
57 | }
58 |
59 | if !reflect.DeepEqual(tt.args.consumer, tt.wants.consumer) {
60 | t.Errorf("p = %v, want %v", tt.args.consumer, tt.wants.consumer)
61 | }
62 | })
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/protocol/nats_jetstream/v2/subscriber.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package nats_jetstream
7 |
8 | import (
9 | "github.com/nats-io/nats.go"
10 | )
11 |
12 | // The Subscriber interface allows us to configure how the subscription is created
13 | type Subscriber interface {
14 | Subscribe(jsm nats.JetStreamContext, subject string, cb nats.MsgHandler, opts ...nats.SubOpt) (*nats.Subscription, error)
15 | }
16 |
17 | // RegularSubscriber creates regular subscriptions
18 | type RegularSubscriber struct {
19 | }
20 |
21 | // Subscribe implements Subscriber.Subscribe
22 | func (s *RegularSubscriber) Subscribe(jsm nats.JetStreamContext, subject string, cb nats.MsgHandler, opts ...nats.SubOpt) (*nats.Subscription, error) {
23 | return jsm.Subscribe(subject, cb, opts...)
24 | }
25 |
26 | var _ Subscriber = (*RegularSubscriber)(nil)
27 |
28 | // QueueSubscriber creates queue subscriptions
29 | type QueueSubscriber struct {
30 | Queue string
31 | }
32 |
33 | // Subscribe implements Subscriber.Subscribe
34 | func (s *QueueSubscriber) Subscribe(jsm nats.JetStreamContext, subject string, cb nats.MsgHandler, opts ...nats.SubOpt) (*nats.Subscription, error) {
35 | return jsm.QueueSubscribe(subject, s.Queue, cb, opts...)
36 | }
37 |
38 | var _ Subscriber = (*QueueSubscriber)(nil)
39 |
--------------------------------------------------------------------------------
/protocol/nats_jetstream/v3/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/protocol/nats_jetstream/v3
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | replace github.com/cloudevents/sdk-go/v2 => ../../../v2
8 |
9 | require (
10 | github.com/cloudevents/sdk-go/v2 v2.16.0
11 | github.com/nats-io/nats.go v1.42.0
12 | )
13 |
14 | require (
15 | github.com/davecgh/go-spew v1.1.1 // indirect
16 | github.com/google/go-cmp v0.7.0 // indirect
17 | github.com/json-iterator/go v1.1.12 // indirect
18 | github.com/klauspost/compress v1.18.0 // indirect
19 | github.com/kr/text v0.2.0 // indirect
20 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
21 | github.com/modern-go/reflect2 v1.0.2 // indirect
22 | github.com/nats-io/nkeys v0.4.11 // indirect
23 | github.com/nats-io/nuid v1.0.1 // indirect
24 | github.com/pmezard/go-difflib v1.0.0 // indirect
25 | github.com/stretchr/testify v1.10.0 // indirect
26 | golang.org/x/crypto v0.38.0 // indirect
27 | golang.org/x/sys v0.33.0 // indirect
28 | gopkg.in/yaml.v3 v3.0.1 // indirect
29 | )
30 |
--------------------------------------------------------------------------------
/protocol/pubsub/v2/attributes.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package pubsub
7 |
8 | import (
9 | "context"
10 |
11 | "github.com/cloudevents/sdk-go/v2/binding"
12 | )
13 |
14 | type withCustomAttributes struct{}
15 |
16 | func AttributesFrom(ctx context.Context) map[string]string {
17 | return binding.GetOrDefaultFromCtx(ctx, withCustomAttributes{}, make(map[string]string)).(map[string]string)
18 | }
19 |
20 | // WithCustomAttributes sets Message Attributes without any CloudEvent logic.
21 | // Note that this function is not intended for CloudEvent Extensions or any `ce-`-prefixed Attributes.
22 | // For these please see `Event` and `Event.SetExtension`.
23 | func WithCustomAttributes(ctx context.Context, attrs map[string]string) context.Context {
24 | return context.WithValue(ctx, withCustomAttributes{}, attrs)
25 | }
26 |
--------------------------------------------------------------------------------
/protocol/pubsub/v2/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package pubsub implements a Pub/Sub binding using google.cloud.com/go/pubsub module
8 |
9 | PubSub Messages can be modified beyond what CloudEvents cover by using `WithOrderingKey`
10 | or `WithCustomAttributes`. See function docs for more details.
11 | */
12 | package pubsub
13 |
--------------------------------------------------------------------------------
/protocol/stan/v2/context.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package stan
7 |
8 | import (
9 | "context"
10 | "github.com/cloudevents/sdk-go/v2/binding"
11 | )
12 |
13 | // MsgMetadata holds metadata of a received *stan.Msg. This information is kept in a separate struct so that users
14 | // cannot interact with the underlying message outside of the SDK.
15 | type MsgMetadata struct {
16 | Sequence uint64
17 | Redelivered bool
18 | RedeliveryCount uint32
19 | }
20 |
21 | type msgKeyType struct{}
22 |
23 | var msgKey msgKeyType
24 |
25 | // MetadataContextDecorator returns an inbound context decorator which adds STAN message metadata to
26 | // the current context. If the inbound message is not a *stan.Message then this decorator is a no-op.
27 | func MetadataContextDecorator() func(context.Context, binding.Message) context.Context {
28 | return func(ctx context.Context, m binding.Message) context.Context {
29 | if msg, ok := m.(*Message); ok {
30 | return context.WithValue(ctx, msgKey, MsgMetadata{
31 | Sequence: msg.Msg.Sequence,
32 | Redelivered: msg.Msg.Redelivered,
33 | RedeliveryCount: msg.Msg.RedeliveryCount,
34 | })
35 | }
36 |
37 | return ctx
38 | }
39 | }
40 |
41 | // MessageMetadataFrom extracts the STAN message metadata from the provided ctx. The bool return parameter is true if
42 | // the metadata was set on the context, or false otherwise.
43 | func MessageMetadataFrom(ctx context.Context) (MsgMetadata, bool) {
44 | if v, ok := ctx.Value(msgKey).(MsgMetadata); ok {
45 | return v, true
46 | }
47 |
48 | return MsgMetadata{}, false
49 | }
50 |
--------------------------------------------------------------------------------
/protocol/stan/v2/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package stan implements the CloudEvent transport implementation using NATS Streaming.
8 | */
9 | package stan
10 |
--------------------------------------------------------------------------------
/protocol/stan/v2/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/protocol/stan/v2
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | replace github.com/cloudevents/sdk-go/v2 => ../../../v2
8 |
9 | require (
10 | github.com/cloudevents/sdk-go/v2 v2.16.0
11 | github.com/nats-io/stan.go v0.10.4
12 | )
13 |
14 | require (
15 | github.com/gogo/protobuf v1.3.2 // indirect
16 | github.com/json-iterator/go v1.1.12 // indirect
17 | github.com/klauspost/compress v1.18.0 // indirect
18 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
19 | github.com/modern-go/reflect2 v1.0.2 // indirect
20 | github.com/nats-io/nats-server/v2 v2.10.27 // indirect
21 | github.com/nats-io/nats-streaming-server v0.25.6 // indirect
22 | github.com/nats-io/nats.go v1.42.0 // indirect
23 | github.com/nats-io/nkeys v0.4.11 // indirect
24 | github.com/nats-io/nuid v1.0.1 // indirect
25 | golang.org/x/crypto v0.38.0 // indirect
26 | golang.org/x/sys v0.33.0 // indirect
27 | )
28 |
--------------------------------------------------------------------------------
/protocol/stan/v2/subscriber.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package stan
7 |
8 | import "github.com/nats-io/stan.go"
9 |
10 | // The Subscriber interface allows us to configure how the subscription is created
11 | type Subscriber interface {
12 | Subscribe(conn stan.Conn, subject string, cb stan.MsgHandler,
13 | opts ...stan.SubscriptionOption) (stan.Subscription, error)
14 | }
15 |
16 | // RegularSubscriber creates regular subscriptions
17 | type RegularSubscriber struct {
18 | }
19 |
20 | // Subscribe implements Subscriber.Subscribe
21 | func (s *RegularSubscriber) Subscribe(conn stan.Conn, subject string, cb stan.MsgHandler,
22 | opts ...stan.SubscriptionOption) (stan.Subscription, error) {
23 | return conn.Subscribe(subject, cb, opts...)
24 | }
25 |
26 | var _ Subscriber = (*RegularSubscriber)(nil)
27 |
28 | // QueueSubscriber creates queue subscriptions
29 | type QueueSubscriber struct {
30 | QueueGroup string
31 | }
32 |
33 | // Subscribe implements Subscriber.Subscribe
34 | func (s *QueueSubscriber) Subscribe(conn stan.Conn, subject string, cb stan.MsgHandler,
35 | opts ...stan.SubscriptionOption) (stan.Subscription, error) {
36 | return conn.QueueSubscribe(subject, s.QueueGroup, cb, opts...)
37 | }
38 |
39 | var _ Subscriber = (*QueueSubscriber)(nil)
40 |
--------------------------------------------------------------------------------
/protocol/stan/v2/write_message.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package stan
7 |
8 | import (
9 | "context"
10 | "github.com/cloudevents/sdk-go/v2/binding"
11 | "github.com/cloudevents/sdk-go/v2/binding/format"
12 | "io"
13 | )
14 |
15 | // WriteMsg fills the provided writer with the bindings.Message m.
16 | // Using context you can tweak the encoding processing (more details on binding.Write documentation).
17 | func WriteMsg(ctx context.Context, m binding.Message, writer io.ReaderFrom, transformers ...binding.Transformer) error {
18 | structuredWriter := &stanMessageWriter{writer}
19 |
20 | _, err := binding.Write(
21 | ctx,
22 | m,
23 | structuredWriter,
24 | nil,
25 | transformers...,
26 | )
27 | return err
28 | }
29 |
30 | type stanMessageWriter struct {
31 | io.ReaderFrom
32 | }
33 |
34 | func (w *stanMessageWriter) SetStructuredEvent(_ context.Context, _ format.Format, event io.Reader) error {
35 | if _, err := w.ReadFrom(event); err != nil {
36 | return err
37 | }
38 |
39 | return nil
40 | }
41 |
42 | var _ binding.StructuredWriter = (*stanMessageWriter)(nil) // Test it conforms to the interface
43 |
--------------------------------------------------------------------------------
/protocol/ws/v2/context.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package v2
7 |
8 | import (
9 | "context"
10 |
11 | "nhooyr.io/websocket"
12 | )
13 |
14 | type codeKey struct{}
15 |
16 | type reasonKey struct{}
17 |
18 | func WithCloseReason(ctx context.Context, code websocket.StatusCode, reason string) context.Context {
19 | return context.WithValue(context.WithValue(ctx, codeKey{}, code), reasonKey{}, reason)
20 | }
21 |
--------------------------------------------------------------------------------
/protocol/ws/v2/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package ws implements the Websocket protocol binding
8 | */
9 | package v2
10 |
--------------------------------------------------------------------------------
/protocol/ws/v2/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/protocol/ws/v2
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | replace github.com/cloudevents/sdk-go/v2 => ../../../v2
8 |
9 | require (
10 | github.com/cloudevents/sdk-go/v2 v2.16.0
11 | github.com/stretchr/testify v1.10.0
12 | nhooyr.io/websocket v1.8.17
13 | )
14 |
15 | require (
16 | github.com/davecgh/go-spew v1.1.1 // indirect
17 | github.com/google/go-cmp v0.7.0 // indirect
18 | github.com/google/uuid v1.6.0 // indirect
19 | github.com/json-iterator/go v1.1.12 // indirect
20 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
21 | github.com/modern-go/reflect2 v1.0.2 // indirect
22 | github.com/pmezard/go-difflib v1.0.0 // indirect
23 | go.uber.org/multierr v1.11.0 // indirect
24 | go.uber.org/zap v1.27.0 // indirect
25 | gopkg.in/yaml.v3 v3.0.1 // indirect
26 | )
27 |
--------------------------------------------------------------------------------
/protocol/ws/v2/subprotocols.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package v2
7 |
8 | import (
9 | "fmt"
10 |
11 | "nhooyr.io/websocket"
12 |
13 | "github.com/cloudevents/sdk-go/v2/binding/format"
14 | )
15 |
16 | const JsonSubprotocol = "cloudevents.json"
17 |
18 | var SupportedSubprotocols = []string{JsonSubprotocol}
19 |
20 | func resolveFormat(subprotocol string) (format.Format, websocket.MessageType, error) {
21 | switch subprotocol {
22 | case "cloudevents.json":
23 | return format.JSON, websocket.MessageText, nil
24 | default:
25 | return nil, websocket.MessageText, fmt.Errorf("subprotocol not supported: %s", subprotocol)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/protocol/ws/v2/subprotocols_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package v2
7 |
8 | import (
9 | "testing"
10 |
11 | "github.com/stretchr/testify/require"
12 | "nhooyr.io/websocket"
13 |
14 | "github.com/cloudevents/sdk-go/v2/binding/format"
15 | )
16 |
17 | func TestResolveFormat(t *testing.T) {
18 | tests := []struct {
19 | name string
20 | subprotocol string
21 | wantFormat format.Format
22 | wantMessageType websocket.MessageType
23 | }{{
24 | name: "JSON subprotocol",
25 | subprotocol: JsonSubprotocol,
26 | wantFormat: format.JSON,
27 | wantMessageType: websocket.MessageText,
28 | }}
29 | for _, tt := range tests {
30 | t.Run(tt.name, func(t *testing.T) {
31 | fmt, messageType, err := resolveFormat(tt.subprotocol)
32 | require.NoError(t, err)
33 | require.Equal(t, tt.wantFormat, fmt)
34 | require.Equal(t, tt.wantMessageType, messageType)
35 | })
36 | }
37 | }
38 |
39 | func TestResolveFormatError(t *testing.T) {
40 | _, _, err := resolveFormat("lalala")
41 | require.Error(t, err, "subprotocol not supported: lalala")
42 | }
43 |
--------------------------------------------------------------------------------
/samples/amqp/README.md:
--------------------------------------------------------------------------------
1 | # AMQP Samples
2 |
3 | These samples require an AMQP 1.0 broker or router to be running.
4 |
5 | One option is http://qpid.apache.org/components/dispatch-router/index.html
6 | It can be installed via dnf or apt, or from source: https://qpid.apache.org/packages.html
7 | Run `qdrouterd` and the samples will work without any additional configuration.
8 |
9 | ## Sample configuration
10 |
11 | The environment variable AMQP_URL can be set to indicate the location of the broker
12 | and the AMQP node address. It has this form:
13 |
14 | amqp://user:pass@host:port/node
15 |
16 | The default if AMQP_URL is not set is:
17 |
18 | amqp://localhost:5672/test
19 |
20 | *Note*: setting `user:pass` in a URL is not recommended in production,
21 | it is done here to simplify using the samples.
22 |
23 |
24 |
--------------------------------------------------------------------------------
/samples/amqp/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/samples/amqp
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | require (
8 | github.com/Azure/go-amqp v1.4.0
9 | github.com/cloudevents/sdk-go/protocol/amqp/v2 v2.16.0
10 | github.com/cloudevents/sdk-go/v2 v2.16.0
11 | github.com/google/uuid v1.6.0
12 | )
13 |
14 | require (
15 | github.com/json-iterator/go v1.1.12 // indirect
16 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
17 | github.com/modern-go/reflect2 v1.0.2 // indirect
18 | go.uber.org/multierr v1.11.0 // indirect
19 | go.uber.org/zap v1.27.0 // indirect
20 | )
21 |
22 | replace github.com/cloudevents/sdk-go/v2 => ../../v2
23 |
24 | replace github.com/cloudevents/sdk-go/protocol/amqp/v2 => ../../protocol/amqp/v2
25 |
26 | replace github.com/Azure/go-amqp => github.com/Azure/go-amqp v0.17.0
27 |
--------------------------------------------------------------------------------
/samples/gochan/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/samples/gochan
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | require github.com/cloudevents/sdk-go/v2 v2.16.0
8 |
9 | require (
10 | github.com/google/uuid v1.6.0 // indirect
11 | github.com/json-iterator/go v1.1.12 // indirect
12 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
13 | github.com/modern-go/reflect2 v1.0.2 // indirect
14 | go.uber.org/multierr v1.11.0 // indirect
15 | go.uber.org/zap v1.27.0 // indirect
16 | )
17 |
18 | replace github.com/cloudevents/sdk-go/v2 => ../../v2
19 |
--------------------------------------------------------------------------------
/samples/http/receiver-direct/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package main
7 |
8 | import (
9 | "context"
10 | "fmt"
11 | "log"
12 | "net/http"
13 |
14 | cloudevents "github.com/cloudevents/sdk-go/v2"
15 | )
16 |
17 | func main() {
18 | ctx := context.Background()
19 | p, err := cloudevents.NewHTTP()
20 | if err != nil {
21 | log.Fatalf("failed to create protocol: %s", err.Error())
22 | }
23 |
24 | h, err := cloudevents.NewHTTPReceiveHandler(ctx, p, receive)
25 | if err != nil {
26 | log.Fatalf("failed to create handler: %s", err.Error())
27 | }
28 |
29 | log.Printf("will listen on :8080\n")
30 | if err := http.ListenAndServe(":8080", h); err != nil {
31 | log.Fatalf("unable to start http server, %s", err)
32 | }
33 | }
34 |
35 | func receive(ctx context.Context, event cloudevents.Event) {
36 | fmt.Printf("%s", event)
37 | }
38 |
--------------------------------------------------------------------------------
/samples/http/receiver-gin/README.md:
--------------------------------------------------------------------------------
1 | Gin Receiver for CloudEvents
2 | ----------------------------------
3 |
4 | An example of a Gin webframework CloudEvents receiver with a [TektonEvent](https://tekton.dev/docs/pipelines/events/)
5 |
6 | # Steps
7 |
8 | Get dependencies
9 | ```shell
10 | cd samples/
11 | go get
12 |
13 | ```
14 |
15 | Run the app
16 | ```shell
17 | go run main.go
18 | ```
19 |
20 | Send a CloudEvent
21 | ```shell
22 | curl -v \
23 | -H "Ce-Id: e7d95c20-6eb4-4614-946d-27b0ce41c7ff" \
24 | -H "Ce-Source: /apis/namespaces/dimitar/clone-build-n4qhgl" \
25 | -H "Ce-Subject: clone-build-n4qhgl" \
26 | -H "Ce-Specversion: 1.0" \
27 | -H "Ce-Type: dev.tekton.event.pipelinerun.started.v1" \
28 | -H "Content-Type: application/json" \
29 | -d @event.json http://localhost:8080
30 |
31 | ...
32 | < HTTP/1.1 200 OK
33 | ...
34 | ```
35 |
36 | Logs output
37 | ```shell
38 | Got an Event: Context Attributes,
39 | specversion: 1.0
40 | type: dev.tekton.event.pipelinerun.started.v1
41 | source: /apis/namespaces/dimitar/clone-build-n4qhgl
42 | subject: clone-build-n4qhgl
43 | id: e7d95c20-6eb4-4614-946d-27b0ce41c7ff
44 | datacontenttype: application/json
45 | Data,
46 | {
47 | "pipelineRun": {
48 | "metadata": {
49 | "name": "clone-build-n4qhgl",
50 | "namespace": "dimitar",
51 | "uid": "44ef2940-b2d9-4ecb-ad12-808a69972f02",
52 |
53 | .....
54 | }
55 | [GIN] 2023/02/13 - 14:16:51 | 200 | 639.6µs | 127.0.0.1 | POST "/"
56 | ```
57 |
--------------------------------------------------------------------------------
/samples/http/receiver-gin/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "net/http"
6 |
7 | "github.com/rs/zerolog/log"
8 |
9 | cloudevents "github.com/cloudevents/sdk-go/v2"
10 | "github.com/gin-gonic/gin"
11 | )
12 |
13 | func receive(event cloudevents.Event) {
14 | fmt.Printf("Got an Event: %s", event)
15 | }
16 |
17 | func index(c *gin.Context) {
18 | c.JSON(http.StatusOK, "Welcome to CloudEvents")
19 | }
20 |
21 | func healthz(c *gin.Context) {
22 | c.String(http.StatusOK, "OK")
23 | }
24 |
25 | func cloudEventsHandler() gin.HandlerFunc {
26 | return func(c *gin.Context) {
27 | p, err := cloudevents.NewHTTP()
28 | if err != nil {
29 | log.Fatal().
30 | Err(err).
31 | Msg("Failed to create protocol")
32 | }
33 |
34 | ceh, err := cloudevents.NewHTTPReceiveHandler(c, p, receive)
35 | if err != nil {
36 | log.Fatal().
37 | Err(err).
38 | Msg("failed to create handler")
39 | }
40 |
41 | ceh.ServeHTTP(c.Writer, c.Request)
42 | }
43 | }
44 |
45 | func main() {
46 | r := gin.Default()
47 | r.SetTrustedProxies(nil)
48 |
49 | r.GET("/", index)
50 | r.GET("/healthz", healthz)
51 | r.POST("/", cloudEventsHandler())
52 |
53 | log.Fatal().
54 | Err(http.ListenAndServe(":8080", r))
55 | }
56 |
--------------------------------------------------------------------------------
/samples/http/receiver-gorilla/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package main
7 |
8 | import (
9 | "context"
10 | "encoding/json"
11 | "fmt"
12 | "log"
13 | "net/http"
14 |
15 | "github.com/gorilla/mux"
16 |
17 | cloudevents "github.com/cloudevents/sdk-go/v2"
18 | )
19 |
20 | func main() {
21 | ctx := context.Background()
22 | p, err := cloudevents.NewHTTP()
23 | if err != nil {
24 | log.Fatalf("failed to create protocol: %s", err.Error())
25 | }
26 |
27 | h, err := cloudevents.NewHTTPReceiveHandler(ctx, p, receive)
28 | if err != nil {
29 | log.Fatalf("failed to create handler: %s", err.Error())
30 | }
31 |
32 | // Use a gorilla mux implementation for the overall http handler.
33 | router := mux.NewRouter()
34 |
35 | router.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
36 | // an example API handler
37 | json.NewEncoder(w).Encode(map[string]bool{"ok": true})
38 | })
39 |
40 | router.Handle("/", h)
41 |
42 | log.Printf("will listen on :8080\n")
43 | if err := http.ListenAndServe(":8080", router); err != nil {
44 | log.Fatalf("unable to start http server, %s", err)
45 | }
46 | }
47 |
48 | func receive(ctx context.Context, event cloudevents.Event) {
49 | fmt.Printf("Got an Event: %s", event)
50 | }
51 |
--------------------------------------------------------------------------------
/samples/http/receiver-protected/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package main
7 |
8 | import (
9 | "context"
10 | "fmt"
11 | "log"
12 |
13 | cloudevents "github.com/cloudevents/sdk-go/v2"
14 | )
15 |
16 | func main() {
17 | ctx := context.Background()
18 | p, err := cloudevents.NewHTTP(
19 | cloudevents.WithDefaultOptionsHandlerFunc([]string{"POST", "OPTIONS"}, 100, []string{"http://localhost:8181"}, true),
20 | )
21 | if err != nil {
22 | log.Fatalf("failed to create protocol: %s", err.Error())
23 | }
24 |
25 | c, err := cloudevents.NewClient(p)
26 | if err != nil {
27 | log.Fatalf("failed to create client, %v", err)
28 | }
29 |
30 | log.Printf("will listen on :8080\n")
31 | log.Fatalf("failed to start receiver: %s", c.StartReceiver(ctx, receive))
32 | }
33 |
34 | func receive(ctx context.Context, event cloudevents.Event) {
35 | fmt.Printf("%s", event)
36 | }
37 |
38 | //
39 | // Testing with:
40 | //
41 | // cd ./tools; PORT=8181 go run ./http/raw/
42 | //
43 | // curl http://localhost:8080 -v -X OPTIONS -H "Origin: http://example.com" -H "WebHook-Request-Origin: http://example.com" -H "WebHook-Request-Callback: http://localhost:8181/do-this?now=true"
44 | //
45 |
--------------------------------------------------------------------------------
/samples/http/receiver-protobuf/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package main
7 |
8 | import (
9 | "context"
10 | "log"
11 |
12 | _ "github.com/cloudevents/sdk-go/binding/format/protobuf/v2"
13 | cloudevents "github.com/cloudevents/sdk-go/v2"
14 | )
15 |
16 | func main() {
17 | ctx := context.Background()
18 | p, err := cloudevents.NewHTTP()
19 | if err != nil {
20 | log.Fatalf("failed to create protocol: %s", err.Error())
21 | }
22 |
23 | c, err := cloudevents.NewClient(p)
24 | if err != nil {
25 | log.Fatalf("failed to create client, %v", err)
26 | }
27 |
28 | log.Printf("will listen on :8080\n")
29 | log.Fatalf("failed to start receiver: %s", c.StartReceiver(ctx, receive))
30 | }
31 |
32 | func receive(ctx context.Context, event cloudevents.Event) {
33 | log.Printf("%s", event)
34 | payload := &Sample{}
35 | if err := event.DataAs(payload); err != nil {
36 | log.Printf("failed to decode protobuf data: %s", err)
37 | return
38 | }
39 | log.Printf("decoded protobuf: %s", payload.Value)
40 | }
41 |
--------------------------------------------------------------------------------
/samples/http/receiver-protobuf/sample.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package pb;
4 |
5 | option go_package = "/;main";
6 |
7 | message Sample { string value = 1; }
8 |
--------------------------------------------------------------------------------
/samples/http/receiver-result/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2022 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package main
7 |
8 | import (
9 | "context"
10 | "fmt"
11 | "log"
12 | "net/http"
13 |
14 | cloudevents "github.com/cloudevents/sdk-go/v2"
15 | )
16 |
17 | func main() {
18 | ctx := context.Background()
19 | p, err := cloudevents.NewHTTP()
20 | if err != nil {
21 | log.Fatalf("failed to create protocol: %s", err.Error())
22 | }
23 |
24 | c, err := cloudevents.NewClient(p)
25 | if err != nil {
26 | log.Fatalf("failed to create client, %v", err)
27 | }
28 |
29 | log.Printf("will listen on :8080\n")
30 | log.Fatalf("failed to start receiver: %s", c.StartReceiver(ctx, receive))
31 | }
32 |
33 | func receive(ctx context.Context, event cloudevents.Event) cloudevents.Result {
34 | fmt.Printf("%s", event)
35 | if event.Type() != "com.cloudevents.sample.sent" {
36 | return cloudevents.NewHTTPResult(http.StatusBadRequest, "invalid type of %s", event.Type())
37 | }
38 | return cloudevents.NewHTTPResult(http.StatusOK, "")
39 | }
40 |
--------------------------------------------------------------------------------
/samples/http/receiver-traced/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package main
7 |
8 | import (
9 | "context"
10 | "fmt"
11 | "log"
12 | "net/http"
13 |
14 | cloudevents "github.com/cloudevents/sdk-go/v2"
15 | "go.opencensus.io/plugin/ochttp"
16 | )
17 |
18 | func main() {
19 | ctx := context.Background()
20 | p, err := cloudevents.NewHTTP(cloudevents.WithMiddleware(func(next http.Handler) http.Handler {
21 | return &ochttp.Handler{Handler: next}
22 | }))
23 | if err != nil {
24 | log.Fatalf("failed to create protocol: %s", err.Error())
25 | }
26 |
27 | c, err := cloudevents.NewClient(p)
28 | if err != nil {
29 | log.Fatalf("failed to create client, %v", err)
30 | }
31 |
32 | log.Printf("will listen on :8080\n")
33 | log.Fatalf("failed to start receiver: %s", c.StartReceiver(ctx, receive))
34 | }
35 |
36 | func receive(ctx context.Context, e cloudevents.Event) {
37 | fmt.Printf("%s", e)
38 | }
39 |
--------------------------------------------------------------------------------
/samples/http/receiver/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package main
7 |
8 | import (
9 | "context"
10 | "fmt"
11 | "log"
12 |
13 | cloudevents "github.com/cloudevents/sdk-go/v2"
14 | )
15 |
16 | func main() {
17 | ctx := context.Background()
18 | p, err := cloudevents.NewHTTP()
19 | if err != nil {
20 | log.Fatalf("failed to create protocol: %s", err.Error())
21 | }
22 |
23 | c, err := cloudevents.NewClient(p)
24 | if err != nil {
25 | log.Fatalf("failed to create client, %v", err)
26 | }
27 |
28 | log.Printf("will listen on :8080\n")
29 | log.Fatalf("failed to start receiver: %s", c.StartReceiver(ctx, receive))
30 | }
31 |
32 | func receive(ctx context.Context, event cloudevents.Event) {
33 | fmt.Printf("%s", event)
34 | }
35 |
--------------------------------------------------------------------------------
/samples/http/sender-protobuf/main.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2021 The CloudEvents Authors
3 | // SPDX-License-Identifier: Apache-2.0
4 | //
5 |
6 | package main
7 |
8 | import (
9 | "context"
10 | "log"
11 |
12 | pbcloudevents "github.com/cloudevents/sdk-go/binding/format/protobuf/v2"
13 | cloudevents "github.com/cloudevents/sdk-go/v2"
14 | cehttp "github.com/cloudevents/sdk-go/v2/protocol/http"
15 | )
16 |
17 | func main() {
18 | ctx := cloudevents.ContextWithTarget(context.Background(), "http://localhost:8080/")
19 |
20 | p, err := cloudevents.NewHTTP()
21 | if err != nil {
22 | log.Fatalf("failed to create protocol: %s", err.Error())
23 | }
24 |
25 | c, err := cloudevents.NewClient(p, cloudevents.WithTimeNow(), cloudevents.WithUUIDs())
26 | if err != nil {
27 | log.Fatalf("failed to create client, %v", err)
28 | }
29 |
30 | for i := 0; i < 10; i++ {
31 | data := &Sample{Value: "sample"}
32 | e := cloudevents.NewEvent()
33 | e.SetType("com.cloudevents.sample.sent")
34 | e.SetSource("https://github.com/cloudevents/sdk-go/v2/samples/http/sender-protobuf")
35 | e.SetDataSchema("my-schema-registry://" + string(data.ProtoReflect().Descriptor().FullName()))
36 | _ = e.SetData(pbcloudevents.ContentTypeProtobuf, data)
37 |
38 | res := c.Send(ctx, e)
39 | if cloudevents.IsUndelivered(res) {
40 | log.Printf("Failed to send: %v", res)
41 | } else {
42 | var httpResult *cehttp.Result
43 | if cloudevents.ResultAs(res, &httpResult) {
44 | log.Printf("Sent %d with status code %d", i, httpResult.StatusCode)
45 | } else {
46 | log.Printf("Send did not return an HTTP response: %s", res)
47 | }
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/samples/http/sender-protobuf/sample.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package pb;
4 |
5 | option go_package = "/;main";
6 |
7 | message Sample { string value = 1; }
8 |
--------------------------------------------------------------------------------
/samples/kafka/README.md:
--------------------------------------------------------------------------------
1 | # Kafka samples
2 |
3 | To run the samples, you need a running Kafka cluster.
4 |
5 | To run a sample Kafka cluster using docker:
6 |
7 | ```
8 | docker run --rm --net=host -e ADV_HOST=localhost -e SAMPLEDATA=0 lensesio/fast-data-dev
9 | ```
--------------------------------------------------------------------------------
/samples/kafka/receiver/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package main
7 |
8 | import (
9 | "context"
10 | "fmt"
11 | "log"
12 |
13 | "github.com/IBM/sarama"
14 |
15 | "github.com/cloudevents/sdk-go/protocol/kafka_sarama/v2"
16 | cloudevents "github.com/cloudevents/sdk-go/v2"
17 | )
18 |
19 | func main() {
20 | saramaConfig := sarama.NewConfig()
21 | saramaConfig.Version = sarama.V2_0_0_0
22 |
23 | receiver, err := kafka_sarama.NewConsumer([]string{"127.0.0.1:9092"}, saramaConfig, "test-group-id", "test-topic")
24 | if err != nil {
25 | log.Fatalf("failed to create protocol: %s", err.Error())
26 | }
27 |
28 | defer receiver.Close(context.Background())
29 |
30 | c, err := cloudevents.NewClient(receiver)
31 | if err != nil {
32 | log.Fatalf("failed to create client, %v", err)
33 | }
34 |
35 | log.Printf("will listen consuming topic test-topic\n")
36 | err = c.StartReceiver(context.Background(), receive)
37 | if err != nil {
38 | log.Fatalf("failed to start receiver: %s", err)
39 | } else {
40 | log.Printf("receiver stopped\n")
41 | }
42 | }
43 |
44 | func receive(ctx context.Context, event cloudevents.Event) {
45 | fmt.Printf("%s", event)
46 | }
47 |
--------------------------------------------------------------------------------
/samples/kafka_confluent/README.md:
--------------------------------------------------------------------------------
1 | # Confluent kafka samples
2 |
3 | To run the samples, you need a running Kafka cluster.
4 |
5 | To run a sample Kafka cluster using docker:
6 |
7 | ```
8 | docker run --rm --net=host confluentinc/confluent-local
9 | ```
--------------------------------------------------------------------------------
/samples/kafka_confluent/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/samples/kafka_confluent
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | replace github.com/cloudevents/sdk-go/v2 => ../../v2
8 |
9 | replace github.com/cloudevents/sdk-go/protocol/kafka_confluent/v2 => ./../../protocol/kafka_confluent/v2
10 |
11 | require (
12 | github.com/cloudevents/sdk-go/protocol/kafka_confluent/v2 v2.16.0
13 | github.com/cloudevents/sdk-go/v2 v2.16.0
14 | github.com/confluentinc/confluent-kafka-go/v2 v2.10.0
15 | )
16 |
17 | require (
18 | github.com/google/uuid v1.6.0 // indirect
19 | github.com/json-iterator/go v1.1.12 // indirect
20 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
21 | github.com/modern-go/reflect2 v1.0.2 // indirect
22 | go.uber.org/multierr v1.11.0 // indirect
23 | go.uber.org/zap v1.27.0 // indirect
24 | )
25 |
--------------------------------------------------------------------------------
/samples/mqtt/README.md:
--------------------------------------------------------------------------------
1 | MQTT samples
2 |
3 | To run the samples, you need a running MQTT broker.
4 |
5 | To run a sample MQTT broker using docker:
6 |
7 | ```bash
8 | docker run -it --rm --name mosquitto -p 1883:1883 eclipse-mosquitto:2.0 mosquitto -c /mosquitto-no-auth.conf
9 | ```
--------------------------------------------------------------------------------
/samples/mqtt/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/samples/mqtt
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | require (
8 | github.com/cloudevents/sdk-go/protocol/mqtt_paho/v2 v2.16.0
9 | github.com/cloudevents/sdk-go/v2 v2.16.0
10 | github.com/eclipse/paho.golang v0.22.0
11 | github.com/google/uuid v1.6.0
12 | )
13 |
14 | require (
15 | github.com/json-iterator/go v1.1.12 // indirect
16 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
17 | github.com/modern-go/reflect2 v1.0.2 // indirect
18 | go.uber.org/multierr v1.11.0 // indirect
19 | go.uber.org/zap v1.27.0 // indirect
20 | )
21 |
22 | replace github.com/cloudevents/sdk-go/v2 => ../../v2
23 |
24 | replace github.com/cloudevents/sdk-go/protocol/mqtt_paho/v2 => ../../protocol/mqtt_paho/v2
25 |
--------------------------------------------------------------------------------
/samples/mqtt/receiver/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2023 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package main
7 |
8 | import (
9 | "context"
10 | "fmt"
11 | "log"
12 | "net"
13 |
14 | mqtt_paho "github.com/cloudevents/sdk-go/protocol/mqtt_paho/v2"
15 | cloudevents "github.com/cloudevents/sdk-go/v2"
16 | "github.com/eclipse/paho.golang/paho"
17 | )
18 |
19 | func main() {
20 | ctx := context.Background()
21 | conn, err := net.Dial("tcp", "127.0.0.1:1883")
22 | if err != nil {
23 | log.Fatalf("failed to connect to mqtt broker: %s", err.Error())
24 | }
25 | config := &paho.ClientConfig{
26 | ClientID: "receiver-client-id",
27 | Conn: conn,
28 | }
29 | subscribeOpt := &paho.Subscribe{
30 | Subscriptions: []paho.SubscribeOptions{
31 | {
32 | Topic: "test-topic",
33 | QoS: 0,
34 | },
35 | },
36 | }
37 | p, err := mqtt_paho.New(ctx, config, mqtt_paho.WithSubscribe(subscribeOpt))
38 | if err != nil {
39 | log.Fatalf("failed to create protocol: %s", err.Error())
40 | }
41 | defer p.Close(ctx)
42 |
43 | c, err := cloudevents.NewClient(p)
44 | if err != nil {
45 | log.Fatalf("failed to create client, %v", err)
46 | }
47 |
48 | log.Printf("receiver start consuming messages from test-topic\n")
49 | err = c.StartReceiver(ctx, receive)
50 | if err != nil {
51 | log.Fatalf("failed to start receiver: %s", err)
52 | } else {
53 | log.Printf("receiver stopped\n")
54 | }
55 | }
56 |
57 | func receive(ctx context.Context, event cloudevents.Event) {
58 | fmt.Printf("%s", event)
59 | }
60 |
--------------------------------------------------------------------------------
/samples/nats/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/samples/nats
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | require (
8 | github.com/cloudevents/sdk-go/protocol/nats/v2 v2.16.0
9 | github.com/cloudevents/sdk-go/v2 v2.16.0
10 | github.com/google/uuid v1.6.0
11 | github.com/kelseyhightower/envconfig v1.4.0
12 | )
13 |
14 | require (
15 | github.com/json-iterator/go v1.1.12 // indirect
16 | github.com/klauspost/compress v1.18.0 // indirect
17 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
18 | github.com/modern-go/reflect2 v1.0.2 // indirect
19 | github.com/nats-io/nats.go v1.42.0 // indirect
20 | github.com/nats-io/nkeys v0.4.11 // indirect
21 | github.com/nats-io/nuid v1.0.1 // indirect
22 | go.uber.org/multierr v1.11.0 // indirect
23 | go.uber.org/zap v1.27.0 // indirect
24 | golang.org/x/crypto v0.38.0 // indirect
25 | golang.org/x/sys v0.33.0 // indirect
26 | )
27 |
28 | replace github.com/cloudevents/sdk-go/v2 => ../../v2
29 |
30 | replace github.com/cloudevents/sdk-go/protocol/nats/v2 => ../../protocol/nats/v2
31 |
--------------------------------------------------------------------------------
/samples/nats_jetstream/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/samples/nats_jetstream
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | require (
8 | github.com/cloudevents/sdk-go/protocol/nats_jetstream/v2 v2.16.0
9 | github.com/cloudevents/sdk-go/v2 v2.16.0
10 | github.com/google/uuid v1.6.0
11 | github.com/kelseyhightower/envconfig v1.4.0
12 | )
13 |
14 | require (
15 | github.com/json-iterator/go v1.1.12 // indirect
16 | github.com/klauspost/compress v1.18.0 // indirect
17 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
18 | github.com/modern-go/reflect2 v1.0.2 // indirect
19 | github.com/nats-io/nats.go v1.42.0 // indirect
20 | github.com/nats-io/nkeys v0.4.11 // indirect
21 | github.com/nats-io/nuid v1.0.1 // indirect
22 | go.uber.org/multierr v1.11.0 // indirect
23 | go.uber.org/zap v1.27.0 // indirect
24 | golang.org/x/crypto v0.38.0 // indirect
25 | golang.org/x/sys v0.33.0 // indirect
26 | )
27 |
28 | replace github.com/cloudevents/sdk-go/v2 => ../../v2
29 |
30 | replace github.com/cloudevents/sdk-go/protocol/nats_jetstream/v2 => ./../../protocol/nats_jetstream/v2
31 |
--------------------------------------------------------------------------------
/samples/nats_jetstream/v3/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/samples/nats_jetstream/v3
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | require (
8 | github.com/cloudevents/sdk-go/protocol/nats_jetstream/v3 v3.0.0
9 | github.com/cloudevents/sdk-go/v2 v2.16.0
10 | github.com/google/uuid v1.6.0
11 | github.com/kelseyhightower/envconfig v1.4.0
12 | github.com/nats-io/nats.go v1.42.0
13 | )
14 |
15 | require (
16 | github.com/json-iterator/go v1.1.12 // indirect
17 | github.com/klauspost/compress v1.18.0 // indirect
18 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
19 | github.com/modern-go/reflect2 v1.0.2 // indirect
20 | github.com/nats-io/nkeys v0.4.11 // indirect
21 | github.com/nats-io/nuid v1.0.1 // indirect
22 | go.uber.org/multierr v1.11.0 // indirect
23 | go.uber.org/zap v1.27.0 // indirect
24 | golang.org/x/crypto v0.38.0 // indirect
25 | golang.org/x/sys v0.33.0 // indirect
26 | )
27 |
28 | replace github.com/cloudevents/sdk-go/v2 => ../../../v2
29 |
30 | replace github.com/cloudevents/sdk-go/protocol/nats_jetstream/v3 => ./../../../protocol/nats_jetstream/v3
31 |
--------------------------------------------------------------------------------
/samples/stan/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/samples/stan
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | require (
8 | github.com/cloudevents/sdk-go/protocol/stan/v2 v2.16.0
9 | github.com/cloudevents/sdk-go/v2 v2.16.0
10 | )
11 |
12 | require (
13 | github.com/gogo/protobuf v1.3.2 // indirect
14 | github.com/google/uuid v1.6.0 // indirect
15 | github.com/hashicorp/go-hclog v1.1.0 // indirect
16 | github.com/hashicorp/go-msgpack v1.1.5 // indirect
17 | github.com/hashicorp/go-msgpack/v2 v2.1.3 // indirect
18 | github.com/hashicorp/raft v1.3.9 // indirect
19 | github.com/json-iterator/go v1.1.12 // indirect
20 | github.com/klauspost/compress v1.18.0 // indirect
21 | github.com/minio/highwayhash v1.0.2 // indirect
22 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
23 | github.com/modern-go/reflect2 v1.0.2 // indirect
24 | github.com/nats-io/jwt/v2 v2.2.1-0.20220113022732-58e87895b296 // indirect
25 | github.com/nats-io/nats.go v1.42.0 // indirect
26 | github.com/nats-io/nkeys v0.4.11 // indirect
27 | github.com/nats-io/nuid v1.0.1 // indirect
28 | github.com/nats-io/stan.go v0.10.4 // indirect
29 | github.com/prometheus/procfs v0.7.3 // indirect
30 | go.etcd.io/bbolt v1.3.6 // indirect
31 | go.uber.org/multierr v1.11.0 // indirect
32 | go.uber.org/zap v1.27.0 // indirect
33 | golang.org/x/crypto v0.38.0 // indirect
34 | golang.org/x/sys v0.33.0 // indirect
35 | )
36 |
37 | replace github.com/cloudevents/sdk-go/v2 => ../../v2
38 |
39 | replace github.com/cloudevents/sdk-go/protocol/stan/v2 => ../../protocol/stan/v2
40 |
--------------------------------------------------------------------------------
/samples/stan/receiver/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package main
7 |
8 | import (
9 | "context"
10 | "fmt"
11 | "log"
12 |
13 | cestan "github.com/cloudevents/sdk-go/protocol/stan/v2"
14 | cloudevents "github.com/cloudevents/sdk-go/v2"
15 | )
16 |
17 | func main() {
18 | receiver, err := cestan.NewConsumer("test-cluster", "test-client", "test-subject", cestan.StanOptions())
19 | if err != nil {
20 | log.Fatalf("failed to create protocol: %v", err)
21 | }
22 |
23 | defer receiver.Close(context.Background())
24 |
25 | c, err := cloudevents.NewClient(receiver, cloudevents.WithTimeNow(), cloudevents.WithUUIDs())
26 | if err != nil {
27 | log.Fatalf("failed to create client: %v", err)
28 | }
29 |
30 | log.Printf("will listen consuming topic test-topic\n")
31 | err = c.StartReceiver(context.TODO(), receive)
32 | if err != nil {
33 | log.Fatalf("failed to start receiver: %s", err)
34 | } else {
35 | log.Printf("receiver stopped\n")
36 | }
37 |
38 | }
39 |
40 | func receive(_ context.Context, event cloudevents.Event) {
41 | fmt.Printf("%s", event)
42 | }
43 |
--------------------------------------------------------------------------------
/samples/stan/sender/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package main
7 |
8 | import (
9 | "context"
10 | "log"
11 |
12 | cestan "github.com/cloudevents/sdk-go/protocol/stan/v2"
13 | cloudevents "github.com/cloudevents/sdk-go/v2"
14 | )
15 |
16 | func main() {
17 | s, err := cestan.NewSender("test-cluster", "test-client", "test-subject", cestan.StanOptions())
18 | if err != nil {
19 | log.Fatalf("failed to create protocol: %v", err)
20 | }
21 |
22 | defer s.Close(context.Background())
23 |
24 | c, err := cloudevents.NewClient(s, cloudevents.WithTimeNow(), cloudevents.WithUUIDs())
25 | if err != nil {
26 | log.Fatalf("failed to create client: %v", err)
27 | }
28 |
29 | for i := 0; i < 10; i++ {
30 | e := cloudevents.NewEvent()
31 | e.SetType("com.cloudevents.sample.sent")
32 | e.SetSource("https://github.com/cloudevents/sdk-go/v2/samples/stan/sender")
33 | _ = e.SetData(cloudevents.ApplicationJSON, map[string]interface{}{
34 | "id": i,
35 | "message": "Hello, World!",
36 | })
37 |
38 | if result := c.Send(context.Background(), e); cloudevents.IsUndelivered(result) {
39 | log.Printf("failed to send: %v", err)
40 | } else {
41 | log.Printf("sent: %d, accepted: %t", i, cloudevents.IsACK(result))
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/samples/ws/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/samples/ws
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | require (
8 | github.com/cloudevents/sdk-go/protocol/ws/v2 v2.16.0
9 | github.com/cloudevents/sdk-go/v2 v2.16.0
10 | )
11 |
12 | require (
13 | github.com/google/uuid v1.6.0 // indirect
14 | github.com/json-iterator/go v1.1.12 // indirect
15 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
16 | github.com/modern-go/reflect2 v1.0.2 // indirect
17 | go.uber.org/multierr v1.11.0 // indirect
18 | go.uber.org/zap v1.27.0 // indirect
19 | nhooyr.io/websocket v1.8.17 // indirect
20 | )
21 |
22 | replace github.com/cloudevents/sdk-go/v2 => ../../v2
23 |
24 | replace github.com/cloudevents/sdk-go/protocol/ws/v2 => ../../protocol/ws/v2
25 |
--------------------------------------------------------------------------------
/sql/v2/Makefile:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudevents/sdk-go/a50d97a11f88b611e9cda2727a0f3e617cbcf06e/sql/v2/Makefile
--------------------------------------------------------------------------------
/sql/v2/expression.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package v2
7 |
8 | import cloudevents "github.com/cloudevents/sdk-go/v2"
9 |
10 | // Expression represents a parsed CloudEvents SQL Expression.
11 | type Expression interface {
12 |
13 | // Evaluate the expression using the provided input type.
14 | // The return value can be either int32, bool or string.
15 | // The evaluation fails as soon as an error arises.
16 | Evaluate(event cloudevents.Event) (interface{}, error)
17 | }
18 |
--------------------------------------------------------------------------------
/sql/v2/expression/base_expressions.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package expression
7 |
8 | import cesql "github.com/cloudevents/sdk-go/sql/v2"
9 |
10 | type baseUnaryExpression struct {
11 | child cesql.Expression
12 | }
13 |
14 | type baseBinaryExpression struct {
15 | left cesql.Expression
16 | right cesql.Expression
17 | }
18 |
--------------------------------------------------------------------------------
/sql/v2/expression/comparison_expressions.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package expression
7 |
8 | import (
9 | cesql "github.com/cloudevents/sdk-go/sql/v2"
10 | "github.com/cloudevents/sdk-go/sql/v2/utils"
11 | cloudevents "github.com/cloudevents/sdk-go/v2"
12 | )
13 |
14 | type equalExpression struct {
15 | baseBinaryExpression
16 | equal bool
17 | }
18 |
19 | func (s equalExpression) Evaluate(event cloudevents.Event) (interface{}, error) {
20 | leftVal, err := s.left.Evaluate(event)
21 | if err != nil {
22 | return false, err
23 | }
24 |
25 | rightVal, err := s.right.Evaluate(event)
26 | if err != nil {
27 | return false, err
28 | }
29 |
30 | leftVal, err = utils.Cast(leftVal, cesql.TypeFromVal(rightVal))
31 | if err != nil {
32 | return false, err
33 | }
34 |
35 | return (leftVal == rightVal) == s.equal, nil
36 | }
37 |
38 | func NewEqualExpression(left cesql.Expression, right cesql.Expression) cesql.Expression {
39 | return equalExpression{
40 | baseBinaryExpression: baseBinaryExpression{
41 | left: left,
42 | right: right,
43 | },
44 | equal: true,
45 | }
46 | }
47 |
48 | func NewNotEqualExpression(left cesql.Expression, right cesql.Expression) cesql.Expression {
49 | return equalExpression{
50 | baseBinaryExpression: baseBinaryExpression{
51 | left: left,
52 | right: right,
53 | },
54 | equal: false,
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/sql/v2/expression/exists_expression.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package expression
7 |
8 | import (
9 | cesql "github.com/cloudevents/sdk-go/sql/v2"
10 | "github.com/cloudevents/sdk-go/sql/v2/utils"
11 | cloudevents "github.com/cloudevents/sdk-go/v2"
12 | )
13 |
14 | type existsExpression struct {
15 | identifier string
16 | }
17 |
18 | func (l existsExpression) Evaluate(event cloudevents.Event) (interface{}, error) {
19 | return utils.ContainsAttribute(event, l.identifier), nil
20 | }
21 |
22 | func NewExistsExpression(identifier string) cesql.Expression {
23 | return existsExpression{identifier: identifier}
24 | }
25 |
--------------------------------------------------------------------------------
/sql/v2/expression/identifier_expression.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package expression
7 |
8 | import (
9 | cesql "github.com/cloudevents/sdk-go/sql/v2"
10 | sqlerrors "github.com/cloudevents/sdk-go/sql/v2/errors"
11 | "github.com/cloudevents/sdk-go/sql/v2/utils"
12 | cloudevents "github.com/cloudevents/sdk-go/v2"
13 | )
14 |
15 | type identifierExpression struct {
16 | identifier string
17 | }
18 |
19 | func (l identifierExpression) Evaluate(event cloudevents.Event) (interface{}, error) {
20 | value := utils.GetAttribute(event, l.identifier)
21 | if value == nil {
22 | return false, sqlerrors.NewMissingAttributeError(l.identifier)
23 | }
24 |
25 | return value, nil
26 | }
27 |
28 | func NewIdentifierExpression(identifier string) cesql.Expression {
29 | return identifierExpression{identifier: identifier}
30 | }
31 |
--------------------------------------------------------------------------------
/sql/v2/expression/in_expression.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package expression
7 |
8 | import (
9 | cesql "github.com/cloudevents/sdk-go/sql/v2"
10 | "github.com/cloudevents/sdk-go/sql/v2/utils"
11 | cloudevents "github.com/cloudevents/sdk-go/v2"
12 | )
13 |
14 | type inExpression struct {
15 | leftExpression cesql.Expression
16 | setExpression []cesql.Expression
17 | }
18 |
19 | func (l inExpression) Evaluate(event cloudevents.Event) (interface{}, error) {
20 | leftValue, err := l.leftExpression.Evaluate(event)
21 | if err != nil {
22 | return false, err
23 | }
24 |
25 | for _, rightExpression := range l.setExpression {
26 | rightValue, err := rightExpression.Evaluate(event)
27 | if err != nil {
28 | return false, err
29 | }
30 |
31 | rightValue, err = utils.Cast(rightValue, cesql.TypeFromVal(leftValue))
32 | if err != nil {
33 | return false, err
34 | }
35 |
36 | if leftValue == rightValue {
37 | return true, nil
38 | }
39 | }
40 |
41 | return false, nil
42 | }
43 |
44 | func NewInExpression(leftExpression cesql.Expression, setExpression []cesql.Expression) cesql.Expression {
45 | return inExpression{leftExpression, setExpression}
46 | }
47 |
--------------------------------------------------------------------------------
/sql/v2/expression/literal_expression.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package expression
7 |
8 | import (
9 | cesql "github.com/cloudevents/sdk-go/sql/v2"
10 | cloudevents "github.com/cloudevents/sdk-go/v2"
11 | )
12 |
13 | type literalExpression struct {
14 | value interface{}
15 | }
16 |
17 | func (l literalExpression) Evaluate(event cloudevents.Event) (interface{}, error) {
18 | return l.value, nil
19 | }
20 |
21 | func NewLiteralExpression(value interface{}) cesql.Expression {
22 | return literalExpression{value: value}
23 | }
24 |
--------------------------------------------------------------------------------
/sql/v2/expression/negate_expression.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package expression
7 |
8 | import (
9 | cesql "github.com/cloudevents/sdk-go/sql/v2"
10 | "github.com/cloudevents/sdk-go/sql/v2/utils"
11 | cloudevents "github.com/cloudevents/sdk-go/v2"
12 | )
13 |
14 | type negateExpression baseUnaryExpression
15 |
16 | func (l negateExpression) Evaluate(event cloudevents.Event) (interface{}, error) {
17 | val, err := l.child.Evaluate(event)
18 | if err != nil {
19 | return int32(0), err
20 | }
21 |
22 | val, err = utils.Cast(val, cesql.IntegerType)
23 | if err != nil {
24 | return int32(0), err
25 | }
26 |
27 | return -(val.(int32)), nil
28 | }
29 |
30 | func NewNegateExpression(child cesql.Expression) cesql.Expression {
31 | return negateExpression{child: child}
32 | }
33 |
--------------------------------------------------------------------------------
/sql/v2/expression/not_expression.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package expression
7 |
8 | import (
9 | cesql "github.com/cloudevents/sdk-go/sql/v2"
10 | "github.com/cloudevents/sdk-go/sql/v2/utils"
11 | cloudevents "github.com/cloudevents/sdk-go/v2"
12 | )
13 |
14 | type notExpression baseUnaryExpression
15 |
16 | func (l notExpression) Evaluate(event cloudevents.Event) (interface{}, error) {
17 | val, err := l.child.Evaluate(event)
18 | if err != nil {
19 | return false, err
20 | }
21 |
22 | val, err = utils.Cast(val, cesql.BooleanType)
23 | if err != nil {
24 | return false, err
25 | }
26 |
27 | return !(val.(bool)), nil
28 | }
29 |
30 | func NewNotExpression(child cesql.Expression) cesql.Expression {
31 | return notExpression{child: child}
32 | }
33 |
--------------------------------------------------------------------------------
/sql/v2/function.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package v2
7 |
8 | import cloudevents "github.com/cloudevents/sdk-go/v2"
9 |
10 | type Function interface {
11 | Name() string
12 | Arity() int
13 | IsVariadic() bool
14 | ArgType(index int) *Type
15 | ReturnType() Type
16 |
17 | Run(event cloudevents.Event, arguments []interface{}) (interface{}, error)
18 | }
19 |
--------------------------------------------------------------------------------
/sql/v2/function/function.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package function
7 |
8 | import (
9 | cesql "github.com/cloudevents/sdk-go/sql/v2"
10 | cloudevents "github.com/cloudevents/sdk-go/v2"
11 | )
12 |
13 | type FuncType func(cloudevents.Event, []interface{}) (interface{}, error)
14 |
15 | type function struct {
16 | name string
17 | fixedArgs []cesql.Type
18 | variadicArgs *cesql.Type
19 | returnType cesql.Type
20 | fn FuncType
21 | }
22 |
23 | func (f function) Name() string {
24 | return f.name
25 | }
26 |
27 | func (f function) Arity() int {
28 | return len(f.fixedArgs)
29 | }
30 |
31 | func (f function) IsVariadic() bool {
32 | return f.variadicArgs != nil
33 | }
34 |
35 | func (f function) ArgType(index int) *cesql.Type {
36 | if index < len(f.fixedArgs) {
37 | return &f.fixedArgs[index]
38 | }
39 | return f.variadicArgs
40 | }
41 |
42 | func (f function) ReturnType() cesql.Type {
43 | return f.returnType
44 | }
45 |
46 | func (f function) Run(event cloudevents.Event, arguments []interface{}) (interface{}, error) {
47 | return f.fn(event, arguments)
48 | }
49 |
50 | func NewFunction(name string,
51 | fixedArgs []cesql.Type,
52 | variadicArgs *cesql.Type,
53 | returnType cesql.Type,
54 | fn FuncType) cesql.Function {
55 | return function{
56 | name: name,
57 | fixedArgs: fixedArgs,
58 | variadicArgs: variadicArgs,
59 | returnType: returnType,
60 | fn: fn,
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/sql/v2/function/integer_functions.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package function
7 |
8 | import (
9 | cesql "github.com/cloudevents/sdk-go/sql/v2"
10 | sqlerrors "github.com/cloudevents/sdk-go/sql/v2/errors"
11 | cloudevents "github.com/cloudevents/sdk-go/v2"
12 | "math"
13 | )
14 |
15 | var AbsFunction function = function{
16 | name: "ABS",
17 | fixedArgs: []cesql.Type{cesql.IntegerType},
18 | variadicArgs: nil,
19 | returnType: cesql.IntegerType,
20 | fn: func(event cloudevents.Event, i []interface{}) (interface{}, error) {
21 | x := i[0].(int32)
22 | if x == math.MinInt32 {
23 | return int32(math.MaxInt32), sqlerrors.NewMathError("integer overflow while computing ABS")
24 | }
25 | if x < 0 {
26 | return -x, nil
27 | }
28 | return x, nil
29 | },
30 | }
31 |
--------------------------------------------------------------------------------
/sql/v2/gen/CESQLParser.tokens:
--------------------------------------------------------------------------------
1 | SPACE=1
2 | LR_BRACKET=2
3 | RR_BRACKET=3
4 | COMMA=4
5 | SINGLE_QUOTE_SYMB=5
6 | DOUBLE_QUOTE_SYMB=6
7 | AND=7
8 | OR=8
9 | XOR=9
10 | NOT=10
11 | STAR=11
12 | DIVIDE=12
13 | MODULE=13
14 | PLUS=14
15 | MINUS=15
16 | EQUAL=16
17 | NOT_EQUAL=17
18 | GREATER=18
19 | GREATER_OR_EQUAL=19
20 | LESS=20
21 | LESS_GREATER=21
22 | LESS_OR_EQUAL=22
23 | LIKE=23
24 | EXISTS=24
25 | IN=25
26 | TRUE=26
27 | FALSE=27
28 | DQUOTED_STRING_LITERAL=28
29 | SQUOTED_STRING_LITERAL=29
30 | INTEGER_LITERAL=30
31 | IDENTIFIER=31
32 | IDENTIFIER_WITH_NUMBER=32
33 | FUNCTION_IDENTIFIER_WITH_UNDERSCORE=33
34 | '('=2
35 | ')'=3
36 | ','=4
37 | '\''=5
38 | '"'=6
39 | 'AND'=7
40 | 'OR'=8
41 | 'XOR'=9
42 | 'NOT'=10
43 | '*'=11
44 | '/'=12
45 | '%'=13
46 | '+'=14
47 | '-'=15
48 | '='=16
49 | '!='=17
50 | '>'=18
51 | '>='=19
52 | '<'=20
53 | '<>'=21
54 | '<='=22
55 | 'LIKE'=23
56 | 'EXISTS'=24
57 | 'IN'=25
58 | 'TRUE'=26
59 | 'FALSE'=27
60 |
--------------------------------------------------------------------------------
/sql/v2/gen/CESQLParserLexer.tokens:
--------------------------------------------------------------------------------
1 | SPACE=1
2 | LR_BRACKET=2
3 | RR_BRACKET=3
4 | COMMA=4
5 | SINGLE_QUOTE_SYMB=5
6 | DOUBLE_QUOTE_SYMB=6
7 | AND=7
8 | OR=8
9 | XOR=9
10 | NOT=10
11 | STAR=11
12 | DIVIDE=12
13 | MODULE=13
14 | PLUS=14
15 | MINUS=15
16 | EQUAL=16
17 | NOT_EQUAL=17
18 | GREATER=18
19 | GREATER_OR_EQUAL=19
20 | LESS=20
21 | LESS_GREATER=21
22 | LESS_OR_EQUAL=22
23 | LIKE=23
24 | EXISTS=24
25 | IN=25
26 | TRUE=26
27 | FALSE=27
28 | DQUOTED_STRING_LITERAL=28
29 | SQUOTED_STRING_LITERAL=29
30 | INTEGER_LITERAL=30
31 | IDENTIFIER=31
32 | IDENTIFIER_WITH_NUMBER=32
33 | FUNCTION_IDENTIFIER_WITH_UNDERSCORE=33
34 | '('=2
35 | ')'=3
36 | ','=4
37 | '\''=5
38 | '"'=6
39 | 'AND'=7
40 | 'OR'=8
41 | 'XOR'=9
42 | 'NOT'=10
43 | '*'=11
44 | '/'=12
45 | '%'=13
46 | '+'=14
47 | '-'=15
48 | '='=16
49 | '!='=17
50 | '>'=18
51 | '>='=19
52 | '<'=20
53 | '<>'=21
54 | '<='=22
55 | 'LIKE'=23
56 | 'EXISTS'=24
57 | 'IN'=25
58 | 'TRUE'=26
59 | 'FALSE'=27
60 |
--------------------------------------------------------------------------------
/sql/v2/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/sql/v2
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | require (
8 | github.com/antlr/antlr4/runtime/Go/antlr v1.4.10
9 | github.com/cloudevents/sdk-go/v2 v2.16.0
10 | github.com/stretchr/testify v1.10.0
11 | gopkg.in/yaml.v2 v2.4.0
12 | sigs.k8s.io/yaml v1.4.0
13 | )
14 |
15 | require (
16 | github.com/davecgh/go-spew v1.1.1 // indirect
17 | github.com/google/go-cmp v0.7.0 // indirect
18 | github.com/google/uuid v1.6.0 // indirect
19 | github.com/json-iterator/go v1.1.12 // indirect
20 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
21 | github.com/modern-go/reflect2 v1.0.2 // indirect
22 | github.com/pmezard/go-difflib v1.0.0 // indirect
23 | go.uber.org/multierr v1.11.0 // indirect
24 | go.uber.org/zap v1.27.0 // indirect
25 | gopkg.in/yaml.v3 v3.0.1 // indirect
26 | )
27 |
28 | replace github.com/cloudevents/sdk-go/v2 => ../../v2
29 |
--------------------------------------------------------------------------------
/sql/v2/parser/case_changing_stream.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package parser
7 |
8 | import (
9 | "unicode"
10 |
11 | "github.com/antlr/antlr4/runtime/Go/antlr"
12 | )
13 |
14 | // Took from https://github.com/antlr/antlr4/blob/master/doc/resources/case_changing_stream.go
15 |
16 | // CaseChangingStream wraps an existing CharStream, but upper cases, or
17 | // lower cases the input before it is tokenized.
18 | type CaseChangingStream struct {
19 | antlr.CharStream
20 |
21 | upper bool
22 | }
23 |
24 | // NewCaseChangingStream returns a new CaseChangingStream that forces
25 | // all tokens read from the underlying stream to be either upper case
26 | // or lower case based on the upper argument.
27 | func NewCaseChangingStream(in antlr.CharStream, upper bool) *CaseChangingStream {
28 | return &CaseChangingStream{in, upper}
29 | }
30 |
31 | // LA gets the value of the symbol at offset from the current position
32 | // from the underlying CharStream and converts it to either upper case
33 | // or lower case.
34 | func (is *CaseChangingStream) LA(offset int) int {
35 | in := is.CharStream.LA(offset)
36 | if in < 0 {
37 | // Such as antlr.TokenEOF which is -1
38 | return in
39 | }
40 | if is.upper {
41 | return int(unicode.ToUpper(rune(in)))
42 | }
43 | return int(unicode.ToLower(rune(in)))
44 | }
45 |
--------------------------------------------------------------------------------
/sql/v2/runtime/test/tck/user_defined_functions.yaml:
--------------------------------------------------------------------------------
1 | name: User defined functions
2 | tests:
3 | - name: HASPREFIX (1)
4 | expression: "HASPREFIX('abcdef', 'ab')"
5 | result: true
6 | - name: HASPREFIX (2)
7 | expression: "HASPREFIX('abcdef', 'abcdef')"
8 | result: true
9 | - name: HASPREFIX (3)
10 | expression: "HASPREFIX('abcdef', '')"
11 | result: true
12 | - name: HASPREFIX (4)
13 | expression: "HASPREFIX('abcdef', 'gh')"
14 | result: false
15 | - name: HASPREFIX (5)
16 | expression: "HASPREFIX('abcdef', 'abcdefg')"
17 | result: false
18 |
19 | - name: KONKAT (1)
20 | expression: "KONKAT('a', 'b', 'c')"
21 | result: abc
22 | - name: KONKAT (2)
23 | expression: "KONKAT()"
24 | result: ""
25 | - name: KONKAT (3)
26 | expression: "KONKAT('a')"
27 | result: "a"
--------------------------------------------------------------------------------
/sql/v2/test/tck/README.md:
--------------------------------------------------------------------------------
1 | # CloudEvents Expression Language TCK
2 |
3 | Each file of this TCK contains a set of test cases, testing one or more specific features of the language.
4 |
5 | The root file structure is composed by:
6 |
7 | * `name`: Name of the test suite contained in the file
8 | * `tests`: List of tests
9 |
10 | Each test definition includes:
11 |
12 | * `name`: Name of the test case
13 | * `expression`: Expression to test.
14 | * `result`: Expected result (OPTIONAL). Can be a boolean, an integer or a string.
15 | * `error`: Expected error (OPTIONAL). If absent, no error is expected.
16 | * `event`: Input event (OPTIONAL). If present, this is a valid event serialized in JSON format. If absent, when testing
17 | the expression, any valid event can be passed.
18 | * `eventOverrides`: Overrides to the input event (OPTIONAL). This might be used when `event` is missing, in order to
19 | define only some specific values, while the other (REQUIRED) attributes can be any value.
20 |
21 | The `error` values could be any of the following:
22 |
23 | * `parse`: Error while parsing the expression
24 | * `math`: Math error while evaluating a math operator
25 | * `cast`: Casting error
26 | * `missingFunction`: Addressed a missing function
27 | * `functionEvaluation`: Error while evaluating a function
28 | * `missingAttribute`: Error due to a missing attribute
29 | * `generic`: A generic error
30 |
--------------------------------------------------------------------------------
/sql/v2/test/tck/case_sensitivity.yaml:
--------------------------------------------------------------------------------
1 | name: Case sensitivity
2 | tests:
3 | - name: TRUE
4 | expression: TRUE
5 | result: true
6 | - name: true
7 | expression: true
8 | result: true
9 | - name: tRuE
10 | expression: tRuE
11 | result: true
12 |
13 | - name: FALSE
14 | expression: FALSE
15 | result: false
16 | - name: false
17 | expression: false
18 | result: false
19 | - name: FaLsE
20 | expression: FaLsE
21 | result: false
22 |
23 | - name: String literals casing preserved
24 | expression: "'aBcD'"
25 | result: aBcD
26 |
--------------------------------------------------------------------------------
/sql/v2/test/tck/context_attributes_access.yaml:
--------------------------------------------------------------------------------
1 | name: Context attributest test
2 | tests:
3 | - name: Access to required attribute
4 | expression: id
5 | eventOverrides:
6 | id: myId
7 | result: myId
8 | - name: Access to optional attribute
9 | expression: subject
10 | eventOverrides:
11 | subject: mySubject
12 | result: mySubject
13 | - name: Absent optional attribute
14 | expression: subject
15 | event:
16 | specversion: "1.0"
17 | id: myId
18 | source: localhost.localdomain
19 | type: myType
20 | result: false
21 | error: missingAttribute
22 | - name: Access to optional boolean extension
23 | expression: mybool
24 | eventOverrides:
25 | mybool: true
26 | result: true
27 | - name: Access to optional integer extension
28 | expression: myint
29 | eventOverrides:
30 | myint: 10
31 | result: 10
32 | - name: Access to optional string extension
33 | expression: myext
34 | eventOverrides:
35 | myext: "my extension"
36 | result: "my extension"
37 | - name: URL type cohercion to string
38 | expression: source
39 | event:
40 | specversion: "1.0"
41 | id: myId
42 | source: "http://localhost/source"
43 | type: myType
44 | result: "http://localhost/source"
45 | - name: Timestamp type cohercion to string
46 | expression: time
47 | event:
48 | specversion: "1.0"
49 | id: myId
50 | source: "http://localhost/source"
51 | type: myType
52 | time: 2018-04-26T14:48:09+02:00
53 | result: 2018-04-26T14:48:09+02:00
54 |
--------------------------------------------------------------------------------
/sql/v2/test/tck/integer_builtin_functions.yaml:
--------------------------------------------------------------------------------
1 | name: Integer builtin functions
2 | tests:
3 | - name: ABS (1)
4 | expression: ABS(10)
5 | result: 10
6 | - name: ABS (2)
7 | expression: ABS(-10)
8 | result: 10
9 | - name: ABS (3)
10 | expression: ABS(0)
11 | result: 0
12 | - name: ABS overflow
13 | expression: ABS(-2147483648)
14 | result: 2147483647
15 | error: math
16 |
17 |
--------------------------------------------------------------------------------
/sql/v2/test/tck/literals.yaml:
--------------------------------------------------------------------------------
1 | name: Literals
2 | tests:
3 | - name: TRUE literal
4 | expression: TRUE
5 | result: true
6 | - name: FALSE literal
7 | expression: FALSE
8 | result: false
9 |
10 | - name: 0 literal
11 | expression: 0
12 | result: 0
13 | - name: 1 literal
14 | expression: 1
15 | result: 1
16 |
17 | - name: String literal single quoted
18 | expression: "'abc'"
19 | result: abc
20 | - name: String literal double quoted
21 | expression: "\"abc\""
22 | result: abc
23 |
24 | - name: String literal single quoted with case
25 | expression: "'aBc'"
26 | result: aBc
27 | - name: String literal double quoted with case
28 | expression: "\"AbC\""
29 | result: AbC
30 |
31 | - name: Escaped string literal (1)
32 | expression: "'a\"b\\'c'"
33 | result: a"b'c
34 | - name: Escaped string literal (2)
35 | expression: "\"a'b\\\"c\""
36 | result: a'b"c
37 |
--------------------------------------------------------------------------------
/sql/v2/test/tck/negate_operator.yaml:
--------------------------------------------------------------------------------
1 | name: Negate operator
2 | tests:
3 | - name: Minus 10
4 | expression: -10
5 | result: -10
6 | - name: Minus minus 10
7 | expression: --10
8 | result: 10
9 |
10 | - name: Minus 10 with casting
11 | expression: -'10'
12 | result: -10
13 | - name: Minus minus 10 with casting
14 | expression: --'10'
15 | result: 10
16 |
17 | - name: Minus with boolean cast
18 | expression: -TRUE
19 | result: -1
20 |
21 | - name: Minus with missing attribute
22 | expression: -missing
23 | result: 0
24 | error: missingAttribute
25 |
--------------------------------------------------------------------------------
/sql/v2/test/tck/not_operator.yaml:
--------------------------------------------------------------------------------
1 | name: Not operator
2 | tests:
3 | - name: Not true
4 | expression: NOT TRUE
5 | result: false
6 | - name: Not false
7 | expression: NOT FALSE
8 | result: true
9 |
10 | - name: Not true with casting
11 | expression: NOT 'TRUE'
12 | result: false
13 | - name: Not false 10 with casting
14 | expression: NOT 'FALSE'
15 | result: true
16 |
17 | - name: Not true with casting
18 | expression: NOT 10
19 | result: false
20 |
21 | - name: Not missing attribute
22 | expression: NOT missing
23 | result: false
24 | error: missingAttribute
25 |
--------------------------------------------------------------------------------
/sql/v2/test/tck/parse_errors.yaml:
--------------------------------------------------------------------------------
1 | name: Parsing errors
2 | tests:
3 | - name: No closed parenthesis
4 | expression: ABC(
5 | error: parse
6 |
--------------------------------------------------------------------------------
/sql/v2/test/tck/sub_expression.yaml:
--------------------------------------------------------------------------------
1 | name: Sub expressions
2 | tests:
3 | - name: Sub expression with literal
4 | expression: "(TRUE)"
5 | result: true
6 |
7 | - name: Math (1)
8 | expression: "4 * (2 + 3)"
9 | result: 20
10 | - name: Math (2)
11 | expression: "(2 + 3) * 4"
12 | result: 20
13 |
--------------------------------------------------------------------------------
/sql/v2/types.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package v2
7 |
8 | type Type uint8
9 |
10 | const (
11 | StringType Type = iota
12 | IntegerType
13 | BooleanType
14 | AnyType
15 | )
16 |
17 | func TypePtr(t Type) *Type {
18 | return &t
19 | }
20 |
21 | func (t Type) IsSameType(val interface{}) bool {
22 | return TypeFromVal(val) == t
23 | }
24 |
25 | func (t Type) String() string {
26 | switch t {
27 | case IntegerType:
28 | return "Integer"
29 | case BooleanType:
30 | return "Boolean"
31 | case StringType:
32 | return "String"
33 | }
34 | return "Any"
35 | }
36 |
37 | func (t Type) ZeroValue() interface{} {
38 | switch t {
39 | case StringType:
40 | return ""
41 | case IntegerType:
42 | return 0
43 | case BooleanType:
44 | return false
45 | case AnyType:
46 | // by default, return false
47 | return false
48 | }
49 | return false
50 | }
51 |
52 | func TypeFromVal(val interface{}) Type {
53 | switch val.(type) {
54 | case string:
55 | return StringType
56 | case int32:
57 | return IntegerType
58 | case bool:
59 | return BooleanType
60 | }
61 | return AnyType
62 | }
63 |
--------------------------------------------------------------------------------
/test/benchmark/e2e/benchmark_case.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package e2e
7 |
8 | type BenchmarkCase struct {
9 | PayloadSize int
10 | Parallelism int
11 | OutputSenders int
12 | }
13 |
14 | func GenerateAllBenchmarkCases(
15 | payloadMin int,
16 | payloadMax int,
17 | parallelismMin int,
18 | parallelismMax int,
19 | outputSendersMin int,
20 | outputSendersMax int,
21 | ) []BenchmarkCase {
22 | var cases []BenchmarkCase
23 |
24 | for payload := payloadMin; payload <= payloadMax; payload *= 2 {
25 | for parallelism := parallelismMin; parallelism <= parallelismMax; parallelism += 1 {
26 | for outputSenders := outputSendersMin; outputSenders <= outputSendersMax; outputSenders += 1 {
27 | cases = append(cases, BenchmarkCase{payload, parallelism, outputSenders})
28 | }
29 | }
30 | }
31 |
32 | return cases
33 | }
34 |
--------------------------------------------------------------------------------
/test/benchmark/e2e/benchmark_result.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package e2e
7 |
8 | import (
9 | "encoding/csv"
10 | "strconv"
11 | "testing"
12 | )
13 |
14 | type BenchmarkResult struct {
15 | BenchmarkCase
16 | testing.BenchmarkResult
17 | }
18 |
19 | func (br *BenchmarkResult) record() []string {
20 | return []string{
21 | strconv.Itoa(br.Parallelism),
22 | strconv.Itoa(br.PayloadSize),
23 | strconv.Itoa(br.OutputSenders),
24 | strconv.FormatInt(br.NsPerOp(), 10),
25 | strconv.FormatInt(br.AllocedBytesPerOp(), 10),
26 | }
27 | }
28 |
29 | type BenchmarkResults []BenchmarkResult
30 |
31 | func (br BenchmarkResults) WriteToCsv(writer *csv.Writer) error {
32 | for _, i2 := range br {
33 | err := writer.Write(i2.record())
34 | if err != nil {
35 | return err
36 | }
37 | }
38 | return nil
39 | }
40 |
--------------------------------------------------------------------------------
/test/benchmark/e2e/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | // Package e2e holds end-to-end eventing benchmarks.
7 | package e2e
8 |
--------------------------------------------------------------------------------
/test/benchmark/e2e/http/3d_plot_allocs.gnuplot:
--------------------------------------------------------------------------------
1 | set datafile separator comma
2 | set datafile missing NaN
3 | set xlabel "Parallelism"
4 | set ylabel "Number of output senders"
5 | set zlabel "Memory Allocated/Ops"
6 | payload_size_kb=ARG1
7 | payload_size=payload_size_kb*1024
8 |
9 | print "Plotting with payload size ".payload_size.""
10 |
11 | splot "baseline-binary.csv" using 1:3:($2==payload_size?$5:1/0) title "Baseline Binary ".payload_size_kb."kb" with linespoint, \
12 | "baseline-structured.csv" using 1:3:($2==payload_size?$5:1/0) title "Baseline Structured ".payload_size_kb."kb" with linespoint, \
13 | "binding-structured-to-structured.csv" using 1:3:($2==payload_size?$5:1/0) title "Binding Structured to Structured ".payload_size_kb."kb" with linespoint, \
14 | "binding-structured-to-binary.csv" using 1:3:($2==payload_size?$5:1/0) title "Binding Structured to Binary ".payload_size_kb."kb" with linespoint, \
15 | "binding-binary-to-structured.csv" using 1:3:($2==payload_size?$5:1/0) title "Binding Binary to Structured ".payload_size_kb."kb" with linespoint, \
16 | "binding-binary-to-binary.csv" using 1:3:($2==payload_size?$5:1/0) title "Binding Binary to Binary ".payload_size_kb."kb" with linespoint, \
17 | "client-binary.csv" using 1:3:($2==payload_size?$5:1/0) title "Client Binary ".payload_size_kb."kb" with linespoint, \
18 | "client-structured.csv" using 1:3:($2==payload_size?$5:1/0) title "Client Structured ".payload_size_kb."kb" with linespoint
19 | pause -1
20 |
--------------------------------------------------------------------------------
/test/benchmark/e2e/http/3d_plot_ns.gnuplot:
--------------------------------------------------------------------------------
1 | set datafile separator comma
2 | set datafile missing NaN
3 | set xlabel "Parallelism"
4 | set ylabel "Number of output senders"
5 | set zlabel "Nanoseconds/Ops"
6 | payload_size_kb=ARG1
7 | payload_size=payload_size_kb*1024
8 |
9 | print "Plotting with payload size ".payload_size.""
10 |
11 | splot "baseline-binary.csv" using 1:3:($2==payload_size?$4:1/0) title "Baseline Binary ".payload_size_kb."kb" with linespoint, \
12 | "baseline-structured.csv" using 1:3:($2==payload_size?$4:1/0) title "Baseline Structured ".payload_size_kb."kb" with linespoint, \
13 | "binding-structured-to-structured.csv" using 1:3:($2==payload_size?$4:1/0) title "Binding Structured to Structured ".payload_size_kb."kb" with linespoint, \
14 | "binding-structured-to-binary.csv" using 1:3:($2==payload_size?$4:1/0) title "Binding Structured to Binary ".payload_size_kb."kb" with linespoint, \
15 | "binding-binary-to-structured.csv" using 1:3:($2==payload_size?$4:1/0) title "Binding Binary to Structured ".payload_size_kb."kb" with linespoint, \
16 | "binding-binary-to-binary.csv" using 1:3:($2==payload_size?$4:1/0) title "Binding Binary to Binary ".payload_size_kb."kb" with linespoint, \
17 | "client-binary.csv" using 1:3:($2==payload_size?$4:1/0) title "Client Binary ".payload_size_kb."kb" with linespoint, \
18 | "client-structured.csv" using 1:3:($2==payload_size?$4:1/0) title "Client Structured ".payload_size_kb."kb" with linespoint
19 | pause -1
20 |
--------------------------------------------------------------------------------
/test/benchmark/e2e/http/README.md:
--------------------------------------------------------------------------------
1 | # E2E Benchmark to compare HTTP binding & HTTP transport
2 |
3 | This benchmark aims to provide a comparison between package `github.com/cloudevents/sdk-go/pkg/bindings/http` and `github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http`
4 |
5 | ## Metrics
6 |
7 | Test keys are:
8 |
9 | * Parallelism (Configuration of `GOMAXPROCS` value, from 1 to `runtime.NumCPU()`)
10 | * Payload size in kb
11 |
12 | ## Run and visualize results
13 |
14 | ### Build
15 |
16 | ```shell script
17 | go build main.go
18 | ```
19 |
20 | ### Run all tests
21 |
22 | ```shell script
23 | ./main --bench=baseline > baseline.csv && ./main --bench=receiver-sender > receiver-sender.csv && ./main --bench=client > client.csv
24 | ```
25 |
26 | ### Plot results
27 |
28 | An example plot script is provided to plot parallelism - nanoseconds/ops, given the payload size:
29 |
30 | ```shell script
31 | gnuplot -c plot_parallelism_ns.gnuplot
32 | ```
33 |
34 | Example:
35 |
36 | ```shell script
37 | gnuplot -c plot_parallelism_ns.gnuplot 16
38 | ```
39 |
--------------------------------------------------------------------------------
/test/conformance/kafka_steps_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package conformance
7 |
8 | import (
9 | "context"
10 |
11 | "github.com/IBM/sarama"
12 | "github.com/cloudevents/sdk-go/protocol/kafka_sarama/v2"
13 | "github.com/cloudevents/sdk-go/v2/binding"
14 | "github.com/cucumber/godog"
15 | )
16 |
17 | var consumerMessage *sarama.ConsumerMessage
18 |
19 | func KafkaFeatureContext(ctx *godog.ScenarioContext) {
20 | ctx.BeforeScenario(func(*godog.Scenario) {
21 | consumerMessage = nil
22 | })
23 | ctx.Step(`^Kafka Protocol Binding is supported$`, func() error {
24 | return nil
25 | })
26 |
27 | ctx.Step(`^a Kafka message with payload:$`, func(payload *godog.DocString) error {
28 | consumerMessage = &sarama.ConsumerMessage{
29 | Value: []byte(payload.Content),
30 | }
31 |
32 | return nil
33 | })
34 |
35 | ctx.Step(`^Kafka headers:$`, func(headers *godog.Table) error {
36 | consumerMessage.Headers = make([]*sarama.RecordHeader, len(headers.Rows))
37 |
38 | for i, row := range headers.Rows {
39 | var key = row.Cells[0].Value
40 | var value = row.Cells[1].Value
41 | consumerMessage.Headers[i] = &sarama.RecordHeader{Key: []byte(key), Value: []byte(value)}
42 | }
43 |
44 | return nil
45 | })
46 |
47 | ctx.Step(`^parsed as Kafka message$`, func() error {
48 | message := kafka_sarama.NewMessageFromConsumerMessage(consumerMessage)
49 |
50 | event, err := binding.ToEvent(context.TODO(), message)
51 |
52 | if err != nil {
53 | return err
54 | }
55 |
56 | currentEvent = event
57 | return nil
58 | })
59 | }
60 |
--------------------------------------------------------------------------------
/test/conformance/run_test.go:
--------------------------------------------------------------------------------
1 | //go:build conformance
2 | // +build conformance
3 |
4 | /*
5 | Copyright 2021 The CloudEvents Authors
6 | SPDX-License-Identifier: Apache-2.0
7 | */
8 | package conformance
9 |
10 | import (
11 | "flag"
12 | "os"
13 | "testing"
14 |
15 | "github.com/cucumber/godog"
16 | "github.com/cucumber/godog/colors"
17 | )
18 |
19 | var opts = godog.Options{
20 | Output: colors.Colored(os.Stdout),
21 | Format: "pretty",
22 | }
23 |
24 | func TestMain(m *testing.M) {
25 | flag.Parse()
26 | if len(flag.Args()) > 0 {
27 | opts.Paths = flag.Args()
28 | } else {
29 | opts.Paths = []string{
30 | "../../conformance/features/",
31 | }
32 | }
33 |
34 | status := godog.TestSuite{
35 | Name: "CloudEvents",
36 | ScenarioInitializer: InitializeScenario,
37 | Options: &opts,
38 | }.Run()
39 |
40 | if st := m.Run(); st > status {
41 | status = st
42 | }
43 | os.Exit(status)
44 | }
45 |
46 | func InitializeScenario(ctx *godog.ScenarioContext) {
47 | CloudEventsFeatureContext(ctx)
48 | HTTPFeatureContext(ctx)
49 | KafkaFeatureContext(ctx)
50 | }
51 |
--------------------------------------------------------------------------------
/test/integration/http/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | // Package http contains HTTP integration test helpers.
7 | package http
8 |
--------------------------------------------------------------------------------
/test/observability/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/test/observability
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | require (
8 | github.com/cloudevents/sdk-go/observability/opentelemetry/v2 v2.16.0
9 | github.com/cloudevents/sdk-go/v2 v2.16.0
10 | github.com/stretchr/testify v1.10.0
11 | go.opentelemetry.io/otel v1.36.0
12 | go.opentelemetry.io/otel/sdk v1.36.0
13 | go.opentelemetry.io/otel/trace v1.36.0
14 | )
15 |
16 | require (
17 | github.com/davecgh/go-spew v1.1.1 // indirect
18 | github.com/felixge/httpsnoop v1.0.4 // indirect
19 | github.com/go-logr/logr v1.4.3 // indirect
20 | github.com/go-logr/stdr v1.2.2 // indirect
21 | github.com/google/uuid v1.6.0 // indirect
22 | github.com/json-iterator/go v1.1.12 // indirect
23 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
24 | github.com/modern-go/reflect2 v1.0.2 // indirect
25 | github.com/pmezard/go-difflib v1.0.0 // indirect
26 | go.opentelemetry.io/auto/sdk v1.1.0 // indirect
27 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
28 | go.opentelemetry.io/otel/metric v1.36.0 // indirect
29 | go.uber.org/multierr v1.11.0 // indirect
30 | go.uber.org/zap v1.27.0 // indirect
31 | golang.org/x/sys v0.33.0 // indirect
32 | gopkg.in/yaml.v3 v3.0.1 // indirect
33 | )
34 |
35 | replace github.com/cloudevents/sdk-go/observability/opentelemetry/v2 => ../../observability/opentelemetry/v2
36 |
37 | replace github.com/cloudevents/sdk-go/v2 => ../../v2
38 |
--------------------------------------------------------------------------------
/test/observability/opentelemetry/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package opentelemetry validates the carrier and observability service instrumentation with the default SDK.
8 |
9 | This package is in a separate module from the instrumentation it tests to
10 | isolate the dependency of the default OTel SDK and not impose this as a transitive
11 | dependency for users.
12 | */
13 | package opentelemetry
14 |
--------------------------------------------------------------------------------
/test/sql/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/test/sql
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | replace github.com/cloudevents/sdk-go/v2 => ./../../v2
8 |
9 | replace github.com/cloudevents/sdk-go/sql/v2 => ./../../sql/v2
10 |
11 | require (
12 | github.com/cloudevents/sdk-go/sql/v2 v2.16.0
13 | github.com/cloudevents/sdk-go/v2 v2.16.0
14 | )
15 |
16 | require (
17 | github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
18 | github.com/google/uuid v1.6.0 // indirect
19 | github.com/json-iterator/go v1.1.12 // indirect
20 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
21 | github.com/modern-go/reflect2 v1.0.2 // indirect
22 | go.uber.org/multierr v1.11.0 // indirect
23 | go.uber.org/zap v1.27.0 // indirect
24 | )
25 |
--------------------------------------------------------------------------------
/test/sql/shortcircuit_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package sql
7 |
8 | import (
9 | "testing"
10 |
11 | cesql "github.com/cloudevents/sdk-go/sql/v2/parser"
12 | cloudevents "github.com/cloudevents/sdk-go/v2"
13 | )
14 |
15 | func TestShortCircuitAND(t *testing.T) {
16 |
17 | sql := "(EXISTS revisiontype AND revisiontype=Branch) OR (branch='master')"
18 |
19 | expression, err := cesql.Parse(string(sql))
20 | evt := cloudevents.NewEvent("1.0")
21 | evt.SetID("evt-1")
22 | evt.SetType("what-ever")
23 | evt.SetSource("/event")
24 | evt.SetExtension("branch", "master")
25 | val, err := expression.Evaluate(evt)
26 |
27 | if err != nil {
28 | t.Errorf("err should be nil: %s", err.Error())
29 | } else {
30 | if !val.(bool) {
31 | t.Errorf("should be true ,but :%s", val)
32 | }
33 | }
34 | }
35 |
36 | func TestShortCircuitOR(t *testing.T) {
37 |
38 | sql := "(branch='master' OR revisiontype=Branch)"
39 |
40 | expression, err := cesql.Parse(string(sql))
41 | evt := cloudevents.NewEvent("1.0")
42 | evt.SetID("evt-1")
43 | evt.SetType("what-ever")
44 | evt.SetSource("/event")
45 | evt.SetExtension("branch", "master")
46 | val, err := expression.Evaluate(evt)
47 |
48 | if err != nil {
49 | t.Errorf("err should be nil: %s", err.Error())
50 | } else {
51 | if !val.(bool) {
52 | t.Errorf("should be true ,but :%s", val)
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/tools/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/tools
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | require github.com/kelseyhightower/envconfig v1.4.0
8 |
--------------------------------------------------------------------------------
/tools/go.sum:
--------------------------------------------------------------------------------
1 | github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
2 | github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
3 |
--------------------------------------------------------------------------------
/tools/http/raw/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package main
7 |
8 | import (
9 | "fmt"
10 | "log"
11 | "net/http"
12 | "net/http/httputil"
13 |
14 | "github.com/kelseyhightower/envconfig"
15 | )
16 |
17 | type RawHTTP struct {
18 | Port int `envconfig:"PORT" default:"8080"`
19 | }
20 |
21 | func (raw *RawHTTP) ServeHTTP(w http.ResponseWriter, r *http.Request) {
22 | w.WriteHeader(http.StatusOK)
23 | if reqBytes, err := httputil.DumpRequest(r, true); err == nil {
24 | log.Printf("Raw HTTP Request:\n%+v", string(reqBytes))
25 | _, _ = w.Write(reqBytes)
26 | } else {
27 | log.Printf("Failed to call DumpRequest: %s", err)
28 | }
29 | fmt.Println("------------------------------")
30 | }
31 |
32 | func main() {
33 | var env RawHTTP
34 | if err := envconfig.Process("", &env); err != nil {
35 | log.Fatalf("Failed to process env var: %s", err)
36 | }
37 | log.Printf("Starting listening on :%d\n", env.Port)
38 | log.Println(http.ListenAndServe(fmt.Sprintf(":%d", env.Port), &env))
39 | }
40 |
--------------------------------------------------------------------------------
/v2/binding/buffering/acks_before_finish_message.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package buffering
7 |
8 | import (
9 | "sync/atomic"
10 |
11 | "github.com/cloudevents/sdk-go/v2/binding"
12 | "github.com/cloudevents/sdk-go/v2/binding/spec"
13 | )
14 |
15 | type acksMessage struct {
16 | binding.Message
17 | requiredAcks int32
18 | }
19 |
20 | func (m *acksMessage) GetAttribute(k spec.Kind) (spec.Attribute, interface{}) {
21 | return m.Message.(binding.MessageMetadataReader).GetAttribute(k)
22 | }
23 |
24 | func (m *acksMessage) GetExtension(s string) interface{} {
25 | return m.Message.(binding.MessageMetadataReader).GetExtension(s)
26 | }
27 |
28 | func (m *acksMessage) GetWrappedMessage() binding.Message {
29 | return m.Message
30 | }
31 |
32 | func (m *acksMessage) Finish(err error) error {
33 | remainingAcks := atomic.AddInt32(&m.requiredAcks, -1)
34 | if remainingAcks == 0 {
35 | return m.Message.Finish(err)
36 | }
37 | return nil
38 | }
39 |
40 | var _ binding.MessageWrapper = (*acksMessage)(nil)
41 |
42 | // WithAcksBeforeFinish returns a wrapper for m that calls m.Finish()
43 | // only after the specified number of acks are received.
44 | // Use it when you need to dispatch a Message using several Sender instances
45 | func WithAcksBeforeFinish(m binding.Message, requiredAcks int) binding.Message {
46 | return &acksMessage{Message: m, requiredAcks: int32(requiredAcks)}
47 | }
48 |
--------------------------------------------------------------------------------
/v2/binding/buffering/copy_message_benchmark_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package buffering
7 |
8 | import (
9 | "context"
10 | "testing"
11 |
12 | . "github.com/cloudevents/sdk-go/v2/binding/test"
13 | . "github.com/cloudevents/sdk-go/v2/test"
14 | )
15 |
16 | var err error
17 |
18 | func BenchmarkBufferMessageFromStructured(b *testing.B) {
19 | e := FullEvent()
20 | input := MustCreateMockStructuredMessage(b, e)
21 | ctx := context.Background()
22 | for i := 0; i < b.N; i++ {
23 | outputMessage, _ := BufferMessage(ctx, input)
24 | err = outputMessage.Finish(nil)
25 | }
26 | }
27 |
28 | func BenchmarkBufferMessageFromBinary(b *testing.B) {
29 | e := FullEvent()
30 | input := MustCreateMockBinaryMessage(e)
31 | ctx := context.Background()
32 | for i := 0; i < b.N; i++ {
33 | outputMessage, _ := BufferMessage(ctx, input)
34 | err = outputMessage.Finish(nil)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/v2/binding/buffering/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | // Package buffering provides APIs for buffered messages.
7 | package buffering
8 |
--------------------------------------------------------------------------------
/v2/binding/finish_message.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package binding
7 |
8 | import "github.com/cloudevents/sdk-go/v2/binding/spec"
9 |
10 | type finishMessage struct {
11 | Message
12 | finish func(error)
13 | }
14 |
15 | func (m *finishMessage) GetAttribute(k spec.Kind) (spec.Attribute, interface{}) {
16 | return m.Message.(MessageMetadataReader).GetAttribute(k)
17 | }
18 |
19 | func (m *finishMessage) GetExtension(s string) interface{} {
20 | return m.Message.(MessageMetadataReader).GetExtension(s)
21 | }
22 |
23 | func (m *finishMessage) GetWrappedMessage() Message {
24 | return m.Message
25 | }
26 |
27 | func (m *finishMessage) Finish(err error) error {
28 | err2 := m.Message.Finish(err) // Finish original message first
29 | if m.finish != nil {
30 | m.finish(err) // Notify callback
31 | }
32 | return err2
33 | }
34 |
35 | var _ MessageWrapper = (*finishMessage)(nil)
36 |
37 | // WithFinish returns a wrapper for m that calls finish() and
38 | // m.Finish() in its Finish().
39 | // Allows code to be notified when a message is Finished.
40 | func WithFinish(m Message, finish func(error)) Message {
41 | return &finishMessage{Message: m, finish: finish}
42 | }
43 |
--------------------------------------------------------------------------------
/v2/binding/format/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package format formats structured events.
8 |
9 | The "application/cloudevents+json" format is built-in and always
10 | available. Other formats may be added.
11 | */
12 | package format
13 |
--------------------------------------------------------------------------------
/v2/binding/spec/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package spec provides spec-version metadata.
8 |
9 | For use by code that maps events using (prefixed) attribute name strings.
10 | Supports handling multiple spec versions uniformly.
11 | */
12 | package spec
13 |
--------------------------------------------------------------------------------
/v2/binding/spec/match_exact_version_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package spec_test
7 |
8 | import (
9 | "net/textproto"
10 | "testing"
11 |
12 | "github.com/stretchr/testify/require"
13 |
14 | "github.com/cloudevents/sdk-go/v2/binding/spec"
15 | "github.com/cloudevents/sdk-go/v2/event"
16 | "github.com/cloudevents/sdk-go/v2/test"
17 | )
18 |
19 | func TestMatchExactVersion(t *testing.T) {
20 | test.EachEvent(t, test.AllVersions([]event.Event{test.FullEvent()}), func(t *testing.T, e event.Event) {
21 | e = e.Clone()
22 | s := spec.WithPrefixMatchExact(
23 | func(s string) string {
24 | if s == "datacontenttype" {
25 | return "Content-Type"
26 | } else {
27 | return textproto.CanonicalMIMEHeaderKey("Ce-" + s)
28 | }
29 | },
30 | "Ce-",
31 | )
32 | sv := s.Version(e.SpecVersion())
33 | require.NotNil(t, sv)
34 |
35 | require.Equal(t, e.ID(), sv.Attribute("Ce-Id").Get(e.Context))
36 | require.Equal(t, "id", sv.Attribute("Ce-Id").Name())
37 |
38 | require.Equal(t, e.DataContentType(), sv.Attribute("Content-Type").Get(e.Context))
39 | require.Equal(t, "datacontenttype", sv.Attribute("Content-Type").Name())
40 | })
41 | }
42 |
--------------------------------------------------------------------------------
/v2/binding/spec/spec_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package spec_test
7 |
8 | import (
9 | "testing"
10 |
11 | "github.com/cloudevents/sdk-go/v2/binding/spec"
12 | "github.com/cloudevents/sdk-go/v2/event"
13 | "github.com/cloudevents/sdk-go/v2/test"
14 | tassert "github.com/stretchr/testify/assert"
15 | "github.com/stretchr/testify/require"
16 | )
17 |
18 | func TestVersions(t *testing.T) {
19 | assert := tassert.New(t)
20 | versions := spec.New()
21 | assert.Equal("specversion", versions.PrefixedSpecVersionName())
22 |
23 | want := []string{"1.0", "0.3"}
24 | all := versions.Versions()
25 | assert.Equal(len(want), len(all))
26 | for i, s := range want {
27 | assert.Equal(s, all[i].String())
28 | assert.Equal(s, all[i].NewContext().GetSpecVersion())
29 | converted := all[i].Convert(event.EventContextV1{}.AsV1())
30 | assert.Equal(s, converted.GetSpecVersion(), "%v %v %v", i, s, converted)
31 | }
32 | assert.Equal(want[0], versions.Latest().NewContext().GetSpecVersion())
33 | }
34 |
35 | func TestSetAttribute(t *testing.T) {
36 | test.EachEvent(t, test.AllVersions([]event.Event{test.MinEvent()}), func(t *testing.T, e event.Event) {
37 | e = e.Clone()
38 | s := spec.WithPrefix("ce_")
39 | sv := s.Version(e.SpecVersion())
40 |
41 | id := "another-id"
42 | require.NoError(t, sv.SetAttribute(e.Context, "ce_id", id))
43 | require.Equal(t, id, e.ID())
44 |
45 | extName := "ce_someExt"
46 | extValue := "extValue"
47 | require.NoError(t, sv.SetAttribute(e.Context, extName, extValue))
48 | require.Equal(t, extValue, e.Extensions()["someext"])
49 | })
50 | }
51 |
--------------------------------------------------------------------------------
/v2/binding/structured_writer.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package binding
7 |
8 | import (
9 | "context"
10 | "io"
11 |
12 | "github.com/cloudevents/sdk-go/v2/binding/format"
13 | )
14 |
15 | // StructuredWriter is used to visit a structured Message and generate a new representation.
16 | //
17 | // Protocols that supports structured encoding should implement this interface to implement direct
18 | // structured to structured encoding and event to structured encoding.
19 | type StructuredWriter interface {
20 | // Event receives an io.Reader for the whole event.
21 | SetStructuredEvent(ctx context.Context, format format.Format, event io.Reader) error
22 | }
23 |
--------------------------------------------------------------------------------
/v2/binding/test/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package test provides utilities to test binding implementations and transformers.
8 | */
9 | package test
10 |
--------------------------------------------------------------------------------
/v2/binding/test/mock_transformer.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package test
7 |
8 | import (
9 | "testing"
10 |
11 | "github.com/stretchr/testify/require"
12 |
13 | "github.com/cloudevents/sdk-go/v2/binding"
14 | )
15 |
16 | type MockTransformer struct {
17 | Invoked int
18 | }
19 |
20 | func (m *MockTransformer) Transform(binding.MessageMetadataReader, binding.MessageMetadataWriter) error {
21 | m.Invoked++
22 | return nil
23 | }
24 |
25 | var _ binding.Transformer = (*MockTransformer)(nil)
26 |
27 | func AssertTransformerInvokedOneTime(t *testing.T, m *MockTransformer) {
28 | require.Equal(t,
29 | 1,
30 | m.Invoked,
31 | "Transformer must be invoked one time, while it was invoked %d",
32 | m.Invoked,
33 | )
34 | }
35 |
--------------------------------------------------------------------------------
/v2/binding/test/mock_unknown_message.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package test
7 |
8 | import (
9 | "context"
10 |
11 | "github.com/cloudevents/sdk-go/v2/binding"
12 | )
13 |
14 | type unknownMessage struct{}
15 |
16 | func (u unknownMessage) ReadEncoding() binding.Encoding {
17 | return binding.EncodingUnknown
18 | }
19 |
20 | func (u unknownMessage) ReadStructured(context.Context, binding.StructuredWriter) error {
21 | return binding.ErrNotStructured
22 | }
23 |
24 | func (u unknownMessage) ReadBinary(context.Context, binding.BinaryWriter) error {
25 | return binding.ErrNotBinary
26 | }
27 |
28 | func (u unknownMessage) Finish(error) error {
29 | return nil
30 | }
31 |
32 | var UnknownMessage binding.Message = unknownMessage{}
33 |
--------------------------------------------------------------------------------
/v2/binding/transformer.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package binding
7 |
8 | // Transformer is an interface that implements a transformation
9 | // process while transferring the event from the Message
10 | // implementation to the provided encoder
11 | //
12 | // When a write function (binding.Write, binding.ToEvent, buffering.CopyMessage, etc.)
13 | // takes Transformer(s) as parameter, it eventually converts the message to a form
14 | // which correctly implements MessageMetadataReader, in order to guarantee that transformation
15 | // is applied
16 | type Transformer interface {
17 | Transform(MessageMetadataReader, MessageMetadataWriter) error
18 | }
19 |
20 | // TransformerFunc is a type alias to implement a Transformer through a function pointer
21 | type TransformerFunc func(MessageMetadataReader, MessageMetadataWriter) error
22 |
23 | func (t TransformerFunc) Transform(r MessageMetadataReader, w MessageMetadataWriter) error {
24 | return t(r, w)
25 | }
26 |
27 | var _ Transformer = (TransformerFunc)(nil)
28 |
29 | // Transformers is a utility alias to run several Transformer
30 | type Transformers []Transformer
31 |
32 | func (t Transformers) Transform(r MessageMetadataReader, w MessageMetadataWriter) error {
33 | for _, transformer := range t {
34 | err := transformer.Transform(r, w)
35 | if err != nil {
36 | return err
37 | }
38 | }
39 | return nil
40 | }
41 |
42 | var _ Transformer = (Transformers)(nil)
43 |
--------------------------------------------------------------------------------
/v2/binding/transformer/add_metadata.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package transformer
7 |
8 | import (
9 | "github.com/cloudevents/sdk-go/v2/binding"
10 | "github.com/cloudevents/sdk-go/v2/binding/spec"
11 | "github.com/cloudevents/sdk-go/v2/types"
12 | )
13 |
14 | // AddAttribute adds a cloudevents attribute (if missing) during the encoding process
15 | func AddAttribute(attributeKind spec.Kind, value interface{}) binding.TransformerFunc {
16 | return SetAttribute(attributeKind, func(i2 interface{}) (i interface{}, err error) {
17 | if types.IsZero(i2) {
18 | return value, nil
19 | }
20 | return i2, nil
21 | })
22 | }
23 |
24 | // AddExtension adds a cloudevents extension (if missing) during the encoding process
25 | func AddExtension(name string, value interface{}) binding.TransformerFunc {
26 | return SetExtension(name, func(i2 interface{}) (i interface{}, err error) {
27 | if types.IsZero(i2) {
28 | return value, nil
29 | }
30 | return i2, nil
31 | })
32 | }
33 |
--------------------------------------------------------------------------------
/v2/binding/transformer/default_metadata.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package transformer
7 |
8 | import (
9 | "time"
10 |
11 | "github.com/cloudevents/sdk-go/v2/binding"
12 | "github.com/cloudevents/sdk-go/v2/binding/spec"
13 | "github.com/cloudevents/sdk-go/v2/types"
14 | )
15 |
16 | var (
17 | // Add the cloudevents time attribute, if missing, to time.Now()
18 | AddTimeNow binding.Transformer = addTimeNow{}
19 | )
20 |
21 | type addTimeNow struct{}
22 |
23 | func (a addTimeNow) Transform(reader binding.MessageMetadataReader, writer binding.MessageMetadataWriter) error {
24 | attr, ti := reader.GetAttribute(spec.Time)
25 | if ti == nil {
26 | return writer.SetAttribute(attr, types.Timestamp{Time: time.Now()})
27 | }
28 | return nil
29 | }
30 |
--------------------------------------------------------------------------------
/v2/binding/transformer/delete_metadata.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package transformer
7 |
8 | import (
9 | "github.com/cloudevents/sdk-go/v2/binding"
10 | "github.com/cloudevents/sdk-go/v2/binding/spec"
11 | )
12 |
13 | // DeleteAttribute deletes a cloudevents attribute during the encoding process
14 | func DeleteAttribute(attributeKind spec.Kind) binding.TransformerFunc {
15 | return SetAttribute(attributeKind, func(i2 interface{}) (i interface{}, err error) {
16 | return nil, nil
17 | })
18 | }
19 |
20 | // DeleteExtension deletes a cloudevents extension during the encoding process
21 | func DeleteExtension(name string) binding.TransformerFunc {
22 | return SetExtension(name, func(i2 interface{}) (i interface{}, err error) {
23 | return nil, nil
24 | })
25 | }
26 |
--------------------------------------------------------------------------------
/v2/binding/transformer/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | // Package transformer provides methods for creating event message transformers.
7 | package transformer
8 |
--------------------------------------------------------------------------------
/v2/binding/transformer/version.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package transformer
7 |
8 | import (
9 | "github.com/cloudevents/sdk-go/v2/binding"
10 | "github.com/cloudevents/sdk-go/v2/binding/spec"
11 | )
12 |
13 | // Version converts the event context version to the specified one.
14 | func Version(newVersion spec.Version) binding.TransformerFunc {
15 | return func(reader binding.MessageMetadataReader, writer binding.MessageMetadataWriter) error {
16 | _, sv := reader.GetAttribute(spec.SpecVersion)
17 | if newVersion.String() == sv {
18 | return nil
19 | }
20 |
21 | for _, newAttr := range newVersion.Attributes() {
22 | oldAttr, val := reader.GetAttribute(newAttr.Kind())
23 | if oldAttr != nil && val != nil {
24 | // Erase old attr
25 | err := writer.SetAttribute(oldAttr, nil)
26 | if err != nil {
27 | return nil
28 | }
29 | if newAttr.Kind() == spec.SpecVersion {
30 | err = writer.SetAttribute(newAttr, newVersion.String())
31 | if err != nil {
32 | return nil
33 | }
34 | } else {
35 | err = writer.SetAttribute(newAttr, val)
36 | if err != nil {
37 | return nil
38 | }
39 | }
40 | }
41 | }
42 | return nil
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/v2/binding/utils/structured_message.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package utils
7 |
8 | import (
9 | "context"
10 | "io"
11 |
12 | "github.com/cloudevents/sdk-go/v2/binding"
13 | "github.com/cloudevents/sdk-go/v2/binding/format"
14 | )
15 |
16 | type genericStructuredMessage struct {
17 | format format.Format
18 | reader io.Reader
19 | }
20 |
21 | // NewStructuredMessage wraps a format and an io.Reader returning an implementation of Message
22 | // This message *cannot* be read several times safely
23 | func NewStructuredMessage(format format.Format, reader io.Reader) *genericStructuredMessage {
24 | return &genericStructuredMessage{reader: reader, format: format}
25 | }
26 |
27 | var _ binding.Message = (*genericStructuredMessage)(nil)
28 |
29 | func (m *genericStructuredMessage) ReadEncoding() binding.Encoding {
30 | return binding.EncodingStructured
31 | }
32 |
33 | func (m *genericStructuredMessage) ReadStructured(ctx context.Context, encoder binding.StructuredWriter) error {
34 | return encoder.SetStructuredEvent(ctx, m.format, m.reader)
35 | }
36 |
37 | func (m *genericStructuredMessage) ReadBinary(ctx context.Context, encoder binding.BinaryWriter) error {
38 | return binding.ErrNotBinary
39 | }
40 |
41 | func (m *genericStructuredMessage) Finish(err error) error {
42 | if closer, ok := m.reader.(io.ReadCloser); ok {
43 | if err2 := closer.Close(); err2 != nil {
44 | return err2
45 | }
46 | }
47 | return err
48 | }
49 |
--------------------------------------------------------------------------------
/v2/binding/utils/structured_message_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package utils_test
7 |
8 | import (
9 | "bytes"
10 | "context"
11 | "io"
12 | "testing"
13 |
14 | "github.com/stretchr/testify/require"
15 |
16 | "github.com/cloudevents/sdk-go/v2/binding"
17 | "github.com/cloudevents/sdk-go/v2/binding/format"
18 | "github.com/cloudevents/sdk-go/v2/binding/utils"
19 | "github.com/cloudevents/sdk-go/v2/test"
20 | )
21 |
22 | func TestNewStructuredMessage(t *testing.T) {
23 | testEvent := test.ConvertEventExtensionsToString(t, test.FullEvent())
24 | jsonBytes := test.MustJSON(t, testEvent)
25 |
26 | message := utils.NewStructuredMessage(format.JSON, io.NopCloser(bytes.NewReader(jsonBytes)))
27 |
28 | require.Equal(t, binding.EncodingStructured, message.ReadEncoding())
29 |
30 | event := test.MustToEvent(t, context.TODO(), message)
31 | test.AssertEventEquals(t, testEvent, event)
32 |
33 | require.NoError(t, message.Finish(nil))
34 | }
35 |
--------------------------------------------------------------------------------
/v2/binding/utils/write_structured_message.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package utils
7 |
8 | import (
9 | "context"
10 | "io"
11 |
12 | "github.com/cloudevents/sdk-go/v2/binding"
13 | "github.com/cloudevents/sdk-go/v2/binding/format"
14 | )
15 |
16 | // WriteStructured fills the provided io.Writer with the binding.Message m in structured mode.
17 | // Using context you can tweak the encoding processing (more details on binding.Write documentation).
18 | func WriteStructured(ctx context.Context, m binding.Message, writer io.Writer, transformers ...binding.Transformer) error {
19 | _, err := binding.Write(
20 | ctx,
21 | m,
22 | wsMessageWriter{writer},
23 | nil,
24 | transformers...,
25 | )
26 | return err
27 | }
28 |
29 | type wsMessageWriter struct {
30 | io.Writer
31 | }
32 |
33 | func (w wsMessageWriter) SetStructuredEvent(_ context.Context, _ format.Format, event io.Reader) error {
34 | _, err := io.Copy(w.Writer, event)
35 | if err != nil {
36 | // Try to close anyway
37 | _ = w.tryToClose()
38 | return err
39 | }
40 |
41 | return w.tryToClose()
42 | }
43 |
44 | func (w wsMessageWriter) tryToClose() error {
45 | if closer, ok := w.Writer.(io.WriteCloser); ok {
46 | return closer.Close()
47 | }
48 | return nil
49 | }
50 |
51 | var _ binding.StructuredWriter = wsMessageWriter{} // Test it conforms to the interface
52 |
--------------------------------------------------------------------------------
/v2/client/client_http.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package client
7 |
8 | import (
9 | "github.com/cloudevents/sdk-go/v2/protocol/http"
10 | )
11 |
12 | // NewHTTP provides the good defaults for the common case using an HTTP
13 | // Protocol client.
14 | // The WithTimeNow, and WithUUIDs client options are also applied to the
15 | // client, all outbound events will have a time and id set if not already
16 | // present.
17 | func NewHTTP(opts ...http.Option) (Client, error) {
18 | p, err := http.New(opts...)
19 | if err != nil {
20 | return nil, err
21 | }
22 |
23 | c, err := New(p, WithTimeNow(), WithUUIDs())
24 | if err != nil {
25 | return nil, err
26 | }
27 |
28 | return c, nil
29 | }
30 |
31 | // NewDefault has been replaced by NewHTTP
32 | // Deprecated. To get the same as NewDefault provided, please use NewHTTP with
33 | // the observability service passed as an option, or client.NewClientHTTP from
34 | // package github.com/cloudevents/sdk-go/observability/opencensus/v2/client
35 | var NewDefault = NewHTTP
36 |
--------------------------------------------------------------------------------
/v2/client/client_observed.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package client
7 |
8 | // NewObserved produces a new client with the provided transport object and applied
9 | // client options.
10 | // Deprecated: This now has the same behaviour of New, and will be removed in future releases.
11 | // As New, you must provide the observability service to use.
12 | var NewObserved = New
13 |
--------------------------------------------------------------------------------
/v2/client/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package client holds the recommended entry points for interacting with the CloudEvents Golang SDK. The client wraps
8 | a selected transport. The client adds validation and defaulting for sending events, and flexible receiver method
9 | registration. For full details, read the `client.Client` documentation.
10 | */
11 | package client
12 |
--------------------------------------------------------------------------------
/v2/client/http_receiver.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package client
7 |
8 | import (
9 | "context"
10 | cecontext "github.com/cloudevents/sdk-go/v2/context"
11 | thttp "github.com/cloudevents/sdk-go/v2/protocol/http"
12 | "go.uber.org/zap"
13 | "net/http"
14 | )
15 |
16 | func NewHTTPReceiveHandler(ctx context.Context, p *thttp.Protocol, fn interface{}) (*EventReceiver, error) {
17 | invoker, err := newReceiveInvoker(fn, noopObservabilityService{}, nil, nil, false) //TODO(slinkydeveloper) maybe not nil?
18 | if err != nil {
19 | return nil, err
20 | }
21 |
22 | return &EventReceiver{
23 | p: p,
24 | invoker: invoker,
25 | }, nil
26 | }
27 |
28 | type EventReceiver struct {
29 | p *thttp.Protocol
30 | invoker Invoker
31 | }
32 |
33 | func (r *EventReceiver) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
34 | // Prepare to handle the message if there's one (context cancellation will ensure this closes)
35 | go func() {
36 | ctx := req.Context()
37 | msg, respFn, err := r.p.Respond(ctx)
38 | if err != nil {
39 | cecontext.LoggerFrom(context.TODO()).Debugw("failed to call Respond", zap.Error(err))
40 | } else if err := r.invoker.Invoke(ctx, msg, respFn); err != nil {
41 | cecontext.LoggerFrom(context.TODO()).Debugw("failed to call Invoke", zap.Error(err))
42 | }
43 | }()
44 | r.p.ServeHTTP(rw, req)
45 | }
46 |
--------------------------------------------------------------------------------
/v2/context/context_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package context_test
7 |
8 | import (
9 | "context"
10 | "net/url"
11 | "testing"
12 |
13 | cecontext "github.com/cloudevents/sdk-go/v2/context"
14 | "github.com/google/go-cmp/cmp"
15 | )
16 |
17 | func TestTargetContext(t *testing.T) {
18 | exampleDotCom, _ := url.Parse("http://example.com")
19 |
20 | testCases := map[string]struct {
21 | target string
22 | ctx context.Context
23 | want *url.URL
24 | }{
25 | "todo context, set url": {
26 | ctx: context.TODO(),
27 | target: "http://example.com",
28 | want: exampleDotCom,
29 | },
30 | "bad url": {
31 | ctx: context.TODO(),
32 | target: "%",
33 | },
34 | "already set target": {
35 | ctx: cecontext.WithTarget(context.TODO(), "http://example2.com"),
36 | target: "http://example.com",
37 | want: exampleDotCom,
38 | },
39 | }
40 | for n, tc := range testCases {
41 | t.Run(n, func(t *testing.T) {
42 |
43 | ctx := cecontext.WithTarget(tc.ctx, tc.target)
44 |
45 | got := cecontext.TargetFrom(ctx)
46 |
47 | if diff := cmp.Diff(tc.want, got); diff != "" {
48 | t.Errorf("unexpected (-want, +got) = %v", diff)
49 | }
50 | })
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/v2/context/delegating.go:
--------------------------------------------------------------------------------
1 | package context
2 |
3 | import "context"
4 |
5 | type valuesDelegating struct {
6 | context.Context
7 | parent context.Context
8 | }
9 |
10 | // ValuesDelegating wraps a child and parent context. It will perform Value()
11 | // lookups first on the child, and then fall back to the child. All other calls
12 | // go solely to the child context.
13 | func ValuesDelegating(child, parent context.Context) context.Context {
14 | return &valuesDelegating{
15 | Context: child,
16 | parent: parent,
17 | }
18 | }
19 |
20 | func (c *valuesDelegating) Value(key interface{}) interface{} {
21 | if val := c.Context.Value(key); val != nil {
22 | return val
23 | }
24 | return c.parent.Value(key)
25 | }
26 |
--------------------------------------------------------------------------------
/v2/context/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package context holds the last resort overrides and fyi objects that can be passed to clients and transports added to
8 | context.Context objects.
9 | */
10 | package context
11 |
--------------------------------------------------------------------------------
/v2/context/logger.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package context
7 |
8 | import (
9 | "context"
10 |
11 | "go.uber.org/zap"
12 | )
13 |
14 | // Opaque key type used to store logger
15 | type loggerKeyType struct{}
16 |
17 | var loggerKey = loggerKeyType{}
18 |
19 | // fallbackLogger is the logger is used when there is no logger attached to the context.
20 | var fallbackLogger *zap.SugaredLogger
21 |
22 | func init() {
23 | if logger, err := zap.NewProduction(); err != nil {
24 | // We failed to create a fallback logger.
25 | fallbackLogger = zap.NewNop().Sugar()
26 | } else {
27 | fallbackLogger = logger.Named("fallback").Sugar()
28 | }
29 | }
30 |
31 | // WithLogger returns a new context with the logger injected into the given context.
32 | func WithLogger(ctx context.Context, logger *zap.SugaredLogger) context.Context {
33 | if logger == nil {
34 | return context.WithValue(ctx, loggerKey, fallbackLogger)
35 | }
36 | return context.WithValue(ctx, loggerKey, logger)
37 | }
38 |
39 | // LoggerFrom returns the logger stored in context.
40 | func LoggerFrom(ctx context.Context) *zap.SugaredLogger {
41 | l := ctx.Value(loggerKey)
42 | if l != nil {
43 | if logger, ok := l.(*zap.SugaredLogger); ok {
44 | return logger
45 | }
46 | }
47 | return fallbackLogger
48 | }
49 |
--------------------------------------------------------------------------------
/v2/context/logger_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package context
7 |
8 | import (
9 | "context"
10 | "testing"
11 |
12 | "github.com/google/go-cmp/cmp"
13 | "github.com/google/go-cmp/cmp/cmpopts"
14 | "go.uber.org/zap"
15 | )
16 |
17 | func TestLoggerContext(t *testing.T) {
18 | var namedLogger *zap.SugaredLogger
19 | if logger, err := zap.NewProduction(); err != nil {
20 | t.Fatal(err)
21 | } else {
22 | namedLogger = logger.Named("unittest").Sugar()
23 | }
24 |
25 | nopLogger := zap.NewNop().Sugar()
26 |
27 | testCases := map[string]struct {
28 | logger *zap.SugaredLogger
29 | ctx context.Context
30 | want *zap.SugaredLogger
31 | }{
32 | "todo context, set logger": {
33 | ctx: context.TODO(),
34 | logger: namedLogger,
35 | want: namedLogger,
36 | },
37 | "already set logger": {
38 | ctx: WithLogger(context.TODO(), nopLogger),
39 | logger: namedLogger,
40 | want: namedLogger,
41 | },
42 | }
43 | for n, tc := range testCases {
44 | t.Run(n, func(t *testing.T) {
45 |
46 | ctx := WithLogger(tc.ctx, tc.logger)
47 | got := LoggerFrom(ctx)
48 |
49 | if diff := cmp.Diff(tc.want, got, cmpopts.IgnoreUnexported(zap.SugaredLogger{})); diff != "" {
50 | t.Errorf("unexpected (-want, +got) = %v", diff)
51 | }
52 | })
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/v2/event/content_type.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package event
7 |
8 | const (
9 | TextPlain = "text/plain"
10 | TextJSON = "text/json"
11 | ApplicationJSON = "application/json"
12 | ApplicationXML = "application/xml"
13 | ApplicationCloudEventsJSON = "application/cloudevents+json"
14 | ApplicationCloudEventsBatchJSON = "application/cloudevents-batch+json"
15 | )
16 |
17 | // StringOfApplicationJSON returns a string pointer to "application/json"
18 | func StringOfApplicationJSON() *string {
19 | a := ApplicationJSON
20 | return &a
21 | }
22 |
23 | // StringOfApplicationXML returns a string pointer to "application/xml"
24 | func StringOfApplicationXML() *string {
25 | a := ApplicationXML
26 | return &a
27 | }
28 |
29 | // StringOfTextPlain returns a string pointer to "text/plain"
30 | func StringOfTextPlain() *string {
31 | a := TextPlain
32 | return &a
33 | }
34 |
35 | // StringOfApplicationCloudEventsJSON returns a string pointer to
36 | // "application/cloudevents+json"
37 | func StringOfApplicationCloudEventsJSON() *string {
38 | a := ApplicationCloudEventsJSON
39 | return &a
40 | }
41 |
42 | // StringOfApplicationCloudEventsBatchJSON returns a string pointer to
43 | // "application/cloudevents-batch+json"
44 | func StringOfApplicationCloudEventsBatchJSON() *string {
45 | a := ApplicationCloudEventsBatchJSON
46 | return &a
47 | }
48 |
--------------------------------------------------------------------------------
/v2/event/data_content_encoding.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package event
7 |
8 | const (
9 | Base64 = "base64"
10 | )
11 |
12 | // StringOfBase64 returns a string pointer to "Base64"
13 | func StringOfBase64() *string {
14 | a := Base64
15 | return &a
16 | }
17 |
--------------------------------------------------------------------------------
/v2/event/data_content_encoding_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package event_test
7 |
8 | import (
9 | "testing"
10 |
11 | "github.com/cloudevents/sdk-go/v2/event"
12 |
13 | "github.com/google/go-cmp/cmp"
14 | )
15 |
16 | func TestStringOfBase64(t *testing.T) {
17 | want := strptr("base64")
18 | got := event.StringOfBase64()
19 |
20 | if diff := cmp.Diff(want, got); diff != "" {
21 | t.Errorf("unexpected string (-want, +got) = %v", diff)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/v2/event/datacodec/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package datacodec holds the data codec registry and adds known encoders and decoders supporting media types such as
8 | `application/json` and `application/xml`.
9 | */
10 | package datacodec
11 |
--------------------------------------------------------------------------------
/v2/event/datacodec/json/data.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package json
7 |
8 | import (
9 | "context"
10 | "encoding/json"
11 | "fmt"
12 | "reflect"
13 | )
14 |
15 | // Decode takes `in` as []byte.
16 | // If Event sent the payload as base64, Decoder assumes that `in` is the
17 | // decoded base64 byte array.
18 | func Decode(ctx context.Context, in []byte, out interface{}) error {
19 | if in == nil {
20 | return nil
21 | }
22 | if out == nil {
23 | return fmt.Errorf("out is nil")
24 | }
25 |
26 | if err := json.Unmarshal(in, out); err != nil {
27 | return fmt.Errorf("[json] found bytes \"%s\", but failed to unmarshal: %s", string(in), err.Error())
28 | }
29 | return nil
30 | }
31 |
32 | // Encode attempts to json.Marshal `in` into bytes. Encode will inspect `in`
33 | // and returns `in` unmodified if it is detected that `in` is already a []byte;
34 | // Or json.Marshal errors.
35 | func Encode(ctx context.Context, in interface{}) ([]byte, error) {
36 | if in == nil {
37 | return nil, nil
38 | }
39 |
40 | it := reflect.TypeOf(in)
41 | switch it.Kind() {
42 | case reflect.Slice:
43 | if it.Elem().Kind() == reflect.Uint8 {
44 |
45 | if b, ok := in.([]byte); ok && len(b) > 0 {
46 | // check to see if it is a pre-encoded byte string.
47 | if b[0] == byte('"') || b[0] == byte('{') || b[0] == byte('[') {
48 | return b, nil
49 | }
50 | }
51 |
52 | }
53 | }
54 |
55 | return json.Marshal(in)
56 | }
57 |
--------------------------------------------------------------------------------
/v2/event/datacodec/json/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package json holds the encoder/decoder implementation for `application/json`.
8 | */
9 | package json
10 |
--------------------------------------------------------------------------------
/v2/event/datacodec/text/data.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package text
7 |
8 | import (
9 | "context"
10 | "fmt"
11 | )
12 |
13 | // Text codec converts []byte or string to string and vice-versa.
14 |
15 | func Decode(_ context.Context, in []byte, out interface{}) error {
16 | p, _ := out.(*string)
17 | if p == nil {
18 | return fmt.Errorf("text.Decode out: want *string, got %T", out)
19 | }
20 | *p = string(in)
21 | return nil
22 | }
23 |
24 | func Encode(_ context.Context, in interface{}) ([]byte, error) {
25 | s, ok := in.(string)
26 | if !ok {
27 | return nil, fmt.Errorf("text.Encode in: want string, got %T", in)
28 | }
29 | return []byte(s), nil
30 | }
31 |
--------------------------------------------------------------------------------
/v2/event/datacodec/text/data_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package text_test
7 |
8 | import (
9 | "context"
10 | "testing"
11 |
12 | "github.com/cloudevents/sdk-go/v2/event/datacodec/text"
13 | "github.com/stretchr/testify/assert"
14 | )
15 |
16 | var ctx = context.Background()
17 |
18 | func TestEncode(t *testing.T) {
19 | assert := assert.New(t)
20 |
21 | b, err := text.Encode(ctx, "")
22 | assert.NoError(err)
23 | assert.Empty(b)
24 |
25 | b, err = text.Encode(ctx, "hello😀")
26 | assert.NoError(err)
27 | assert.Equal("hello😀", string(b))
28 |
29 | _, err = text.Encode(ctx, []byte("x"))
30 | assert.EqualError(err, "text.Encode in: want string, got []uint8")
31 | _, err = text.Encode(ctx, nil)
32 | assert.EqualError(err, "text.Encode in: want string, got ")
33 | }
34 |
35 | func TestDecode(t *testing.T) {
36 | assert := assert.New(t)
37 | var s string
38 | assert.NoError(text.Decode(ctx, []byte("bye"), &s))
39 | assert.Equal("bye", s)
40 | assert.NoError(text.Decode(ctx, []byte{}, &s))
41 | assert.Equal("", s)
42 | s = "xxx"
43 | assert.NoError(text.Decode(ctx, nil, &s))
44 | assert.Equal("", s)
45 | }
46 |
--------------------------------------------------------------------------------
/v2/event/datacodec/text/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package text holds the encoder/decoder implementation for `text/plain`.
8 | */
9 | package text
10 |
--------------------------------------------------------------------------------
/v2/event/datacodec/xml/data.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package xml
7 |
8 | import (
9 | "context"
10 | "encoding/xml"
11 | "fmt"
12 | )
13 |
14 | // Decode takes `in` as []byte.
15 | // If Event sent the payload as base64, Decoder assumes that `in` is the
16 | // decoded base64 byte array.
17 | func Decode(ctx context.Context, in []byte, out interface{}) error {
18 | if in == nil {
19 | return nil
20 | }
21 |
22 | if err := xml.Unmarshal(in, out); err != nil {
23 | return fmt.Errorf("[xml] found bytes, but failed to unmarshal: %s %s", err.Error(), string(in))
24 | }
25 | return nil
26 | }
27 |
28 | // Encode attempts to xml.Marshal `in` into bytes. Encode will inspect `in`
29 | // and returns `in` unmodified if it is detected that `in` is already a []byte;
30 | // Or xml.Marshal errors.
31 | func Encode(ctx context.Context, in interface{}) ([]byte, error) {
32 | if b, ok := in.([]byte); ok {
33 | // check to see if it is a pre-encoded byte string.
34 | if len(b) > 0 && b[0] == byte('"') {
35 | return b, nil
36 | }
37 | }
38 |
39 | return xml.Marshal(in)
40 | }
41 |
--------------------------------------------------------------------------------
/v2/event/datacodec/xml/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package xml holds the encoder/decoder implementation for `application/xml`.
8 | */
9 | package xml
10 |
--------------------------------------------------------------------------------
/v2/event/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package event provides primitives to work with CloudEvents specification: https://github.com/cloudevents/spec.
8 | */
9 | package event
10 |
--------------------------------------------------------------------------------
/v2/event/event_validation.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package event
7 |
8 | import (
9 | "fmt"
10 | "strings"
11 | )
12 |
13 | type ValidationError map[string]error
14 |
15 | func (e ValidationError) Error() string {
16 | b := strings.Builder{}
17 | for k, v := range e {
18 | b.WriteString(k)
19 | b.WriteString(": ")
20 | b.WriteString(v.Error())
21 | b.WriteRune('\n')
22 | }
23 | return b.String()
24 | }
25 |
26 | // Validate performs a spec based validation on this event.
27 | // Validation is dependent on the spec version specified in the event context.
28 | func (e Event) Validate() error {
29 | if e.Context == nil {
30 | return ValidationError{"specversion": fmt.Errorf("missing Event.Context")}
31 | }
32 |
33 | errs := map[string]error{}
34 | if e.FieldErrors != nil {
35 | for k, v := range e.FieldErrors {
36 | errs[k] = v
37 | }
38 | }
39 |
40 | if fieldErrors := e.Context.Validate(); fieldErrors != nil {
41 | for k, v := range fieldErrors {
42 | errs[k] = v
43 | }
44 | }
45 |
46 | if len(errs) > 0 {
47 | return ValidationError(errs)
48 | }
49 | return nil
50 | }
51 |
--------------------------------------------------------------------------------
/v2/event/extensions_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package event
7 |
8 | import (
9 | "errors"
10 | "testing"
11 | )
12 |
13 | func TestEvent_validateExtensionName(t *testing.T) {
14 | testCases := map[string]struct {
15 | key string
16 | want error
17 | }{
18 | "empty key": {
19 | key: "",
20 | want: errors.New("bad key, CloudEvents attribute names MUST NOT be empty"),
21 | },
22 | "invalid character": {
23 | key: "invalid_key",
24 | want: errors.New("bad key, CloudEvents attribute names MUST consist of lower-case letters ('a' to 'z'), upper-case letters ('A' to 'Z') or digits ('0' to '9') from the ASCII character set"),
25 | },
26 | "valid key": {
27 | key: "validkey123",
28 | want: nil,
29 | },
30 | }
31 |
32 | for name, tc := range testCases {
33 | t.Run(name, func(t *testing.T) {
34 | err := validateExtensionName(tc.key)
35 | if err != nil && err.Error() != tc.want.Error() || err == nil && tc.want != nil {
36 | t.Errorf("unexpected error, expected: %v, actual: %v", tc.want, err)
37 | }
38 | })
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/v2/extensions/dataref_extension.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package extensions
7 |
8 | import (
9 | "github.com/cloudevents/sdk-go/v2/event"
10 | "net/url"
11 | )
12 |
13 | const DataRefExtensionKey = "dataref"
14 |
15 | // DataRefExtension represents the CloudEvents Dataref (claim check pattern)
16 | // extension for cloudevents contexts,
17 | // See https://github.com/cloudevents/spec/blob/main/cloudevents/extensions/dataref.md
18 | // for more info
19 | type DataRefExtension struct {
20 | DataRef string `json:"dataref"`
21 | }
22 |
23 | // AddDataRefExtension adds the dataref attribute to the cloudevents context
24 | func AddDataRefExtension(e *event.Event, dataRef string) error {
25 | if _, err := url.Parse(dataRef); err != nil {
26 | return err
27 | }
28 | e.SetExtension(DataRefExtensionKey, dataRef)
29 | return nil
30 | }
31 |
32 | // GetDataRefExtension returns any dataref attribute present in the
33 | // cloudevent event/context and a bool to indicate if it was found.
34 | // If not found, the DataRefExtension.DataRef value will be ""
35 | func GetDataRefExtension(e event.Event) (DataRefExtension, bool) {
36 | if dataRefValue, ok := e.Extensions()[DataRefExtensionKey]; ok {
37 | dataRefStr, _ := dataRefValue.(string)
38 | return DataRefExtension{DataRef: dataRefStr}, true
39 | }
40 | return DataRefExtension{}, false
41 | }
42 |
--------------------------------------------------------------------------------
/v2/extensions/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | // Package extensions provides implementations of common event extensions.
7 | package extensions
8 |
--------------------------------------------------------------------------------
/v2/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudevents/sdk-go/v2
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.23.8
6 |
7 | require (
8 | github.com/google/go-cmp v0.7.0
9 | github.com/google/uuid v1.6.0
10 | github.com/json-iterator/go v1.1.12
11 | github.com/stretchr/testify v1.10.0
12 | github.com/valyala/bytebufferpool v1.0.0
13 | go.uber.org/zap v1.27.0
14 | golang.org/x/sync v0.14.0
15 | golang.org/x/time v0.11.0
16 | )
17 |
18 | require (
19 | github.com/davecgh/go-spew v1.1.1 // indirect
20 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
21 | github.com/modern-go/reflect2 v1.0.2 // indirect
22 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
23 | github.com/pmezard/go-difflib v1.0.0 // indirect
24 | go.uber.org/multierr v1.11.0 // indirect
25 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
26 | gopkg.in/yaml.v3 v3.0.1 // indirect
27 | )
28 |
--------------------------------------------------------------------------------
/v2/observability/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package observability holds metrics and tracing common keys.
8 | */
9 | package observability
10 |
--------------------------------------------------------------------------------
/v2/observability/keys.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package observability
7 |
8 | const (
9 | // ClientSpanName is the key used to start spans from the client.
10 | ClientSpanName = "cloudevents.client"
11 |
12 | // metrics/tracing attributes
13 | SpecversionAttr = "cloudevents.specversion"
14 | IdAttr = "cloudevents.id"
15 | TypeAttr = "cloudevents.type"
16 | SourceAttr = "cloudevents.source"
17 | SubjectAttr = "cloudevents.subject"
18 | DatacontenttypeAttr = "cloudevents.datacontenttype"
19 | )
20 |
--------------------------------------------------------------------------------
/v2/protocol/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package protocol defines interfaces to decouple the client package
8 | from protocol implementations.
9 |
10 | Most event sender and receiver applications should not use this
11 | package, they should use the client package. This package is for
12 | infrastructure developers implementing new transports, or intermediary
13 | components like importers, channels or brokers.
14 |
15 | Available protocols:
16 |
17 | * HTTP (using net/http)
18 | * Kafka (using github.com/IBM/sarama)
19 | * AMQP (using pack.ag/amqp)
20 | * Go Channels
21 | * Nats
22 | * Nats Streaming (stan)
23 | * Google PubSub
24 | */
25 | package protocol
26 |
--------------------------------------------------------------------------------
/v2/protocol/error.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package protocol
7 |
8 | import "fmt"
9 |
10 | // ErrTransportMessageConversion is an error produced when the transport
11 | // message can not be converted.
12 | type ErrTransportMessageConversion struct {
13 | fatal bool
14 | handled bool
15 | transport string
16 | message string
17 | }
18 |
19 | // NewErrTransportMessageConversion makes a new ErrTransportMessageConversion.
20 | func NewErrTransportMessageConversion(transport, message string, handled, fatal bool) *ErrTransportMessageConversion {
21 | return &ErrTransportMessageConversion{
22 | transport: transport,
23 | message: message,
24 | handled: handled,
25 | fatal: fatal,
26 | }
27 | }
28 |
29 | // IsFatal reports if this error should be considered fatal.
30 | func (e *ErrTransportMessageConversion) IsFatal() bool {
31 | return e.fatal
32 | }
33 |
34 | // Handled reports if this error should be considered accepted and no further action.
35 | func (e *ErrTransportMessageConversion) Handled() bool {
36 | return e.handled
37 | }
38 |
39 | // Error implements error.Error
40 | func (e *ErrTransportMessageConversion) Error() string {
41 | return fmt.Sprintf("transport %s failed to convert message: %s", e.transport, e.message)
42 | }
43 |
--------------------------------------------------------------------------------
/v2/protocol/gochan/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package gochan implements the CloudEvent transport implementation using go chan.
8 | */
9 | package gochan
10 |
--------------------------------------------------------------------------------
/v2/protocol/gochan/protocol.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package gochan
7 |
8 | import (
9 | "context"
10 |
11 | "github.com/cloudevents/sdk-go/v2/binding"
12 | "github.com/cloudevents/sdk-go/v2/protocol"
13 | )
14 |
15 | const (
16 | defaultChanDepth = 20
17 | )
18 |
19 | // SendReceiver is a reference implementation for using the CloudEvents binding
20 | // integration.
21 | type SendReceiver struct {
22 | sender protocol.SendCloser
23 | receiver protocol.Receiver
24 | }
25 |
26 | func New() *SendReceiver {
27 | ch := make(chan binding.Message, defaultChanDepth)
28 |
29 | return &SendReceiver{
30 | sender: Sender(ch),
31 | receiver: Receiver(ch),
32 | }
33 | }
34 |
35 | func (sr *SendReceiver) Send(ctx context.Context, in binding.Message, transformers ...binding.Transformer) (err error) {
36 | return sr.sender.Send(ctx, in, transformers...)
37 | }
38 |
39 | func (sr *SendReceiver) Receive(ctx context.Context) (binding.Message, error) {
40 | return sr.receiver.Receive(ctx)
41 | }
42 |
43 | func (sr *SendReceiver) Close(ctx context.Context) error {
44 | return sr.sender.Close(ctx)
45 | }
46 |
--------------------------------------------------------------------------------
/v2/protocol/gochan/receiver.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package gochan
7 |
8 | import (
9 | "context"
10 | "fmt"
11 | "github.com/cloudevents/sdk-go/v2/protocol"
12 | "io"
13 |
14 | "github.com/cloudevents/sdk-go/v2/binding"
15 | )
16 |
17 | // Receiver implements Receiver by receiving Messages from a channel.
18 | type Receiver <-chan binding.Message
19 |
20 | func (r Receiver) Receive(ctx context.Context) (binding.Message, error) {
21 | if ctx == nil {
22 | return nil, fmt.Errorf("nil Context")
23 | }
24 |
25 | select {
26 | case <-ctx.Done():
27 | return nil, io.EOF
28 | case m, ok := <-r:
29 | if !ok {
30 | return nil, io.EOF
31 | }
32 | return m, nil
33 | }
34 | }
35 |
36 | var _ protocol.Receiver = (*Receiver)(nil)
37 |
--------------------------------------------------------------------------------
/v2/protocol/gochan/requester.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package gochan
7 |
8 | import (
9 | "context"
10 | "errors"
11 | "fmt"
12 |
13 | "github.com/cloudevents/sdk-go/v2/binding"
14 | "github.com/cloudevents/sdk-go/v2/protocol"
15 | )
16 |
17 | type Requester struct {
18 | Ch chan<- binding.Message
19 | Reply func(message binding.Message) (binding.Message, error)
20 | }
21 |
22 | func (s *Requester) Send(ctx context.Context, m binding.Message, transformers ...binding.Transformer) (err error) {
23 | if ctx == nil {
24 | return fmt.Errorf("nil Context")
25 | } else if m == nil {
26 | return fmt.Errorf("nil Message")
27 | }
28 |
29 | defer func() {
30 | err2 := m.Finish(err)
31 | if err == nil {
32 | err = err2
33 | }
34 | }()
35 | select {
36 | case <-ctx.Done():
37 | return ctx.Err()
38 | case s.Ch <- m:
39 | return nil
40 | }
41 | }
42 |
43 | func (s *Requester) Request(ctx context.Context, m binding.Message, transformers ...binding.Transformer) (res binding.Message, err error) {
44 | defer func() {
45 | err2 := m.Finish(err)
46 | if err == nil {
47 | err = err2
48 | }
49 | }()
50 | select {
51 | case <-ctx.Done():
52 | return nil, ctx.Err()
53 | case s.Ch <- m:
54 | return s.Reply(m)
55 | }
56 | }
57 |
58 | func (s *Requester) Close(ctx context.Context) (err error) {
59 | defer func() {
60 | if recover() != nil {
61 | err = errors.New("trying to close a closed Sender")
62 | }
63 | }()
64 | close(s.Ch)
65 | return nil
66 | }
67 |
68 | var _ protocol.RequesterCloser = (*Requester)(nil)
69 |
--------------------------------------------------------------------------------
/v2/protocol/gochan/responder.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package gochan
7 |
8 | import (
9 | "context"
10 | "fmt"
11 | "io"
12 |
13 | "github.com/cloudevents/sdk-go/v2/binding"
14 | "github.com/cloudevents/sdk-go/v2/protocol"
15 | )
16 |
17 | type ChanResponderResponse struct {
18 | Message binding.Message
19 | Result protocol.Result
20 | }
21 |
22 | // Responder implements Responder by receiving Messages from a channel and outputting the result in an output channel.
23 | // All message received in the `Out` channel must be finished
24 | type Responder struct {
25 | In <-chan binding.Message
26 | Out chan<- ChanResponderResponse
27 | }
28 |
29 | func (r *Responder) Respond(ctx context.Context) (binding.Message, protocol.ResponseFn, error) {
30 | if ctx == nil {
31 | return nil, nil, fmt.Errorf("nil Context")
32 | }
33 |
34 | select {
35 | case <-ctx.Done():
36 | return nil, nil, ctx.Err()
37 | case m, ok := <-r.In:
38 | if !ok {
39 | return nil, nil, io.EOF
40 | }
41 | return m, func(ctx context.Context, message binding.Message, result protocol.Result, transformers ...binding.Transformer) error {
42 | r.Out <- ChanResponderResponse{
43 | Message: message,
44 | Result: result,
45 | }
46 | return nil
47 | }, nil
48 | }
49 | }
50 |
51 | var _ protocol.Responder = (*Responder)(nil)
52 |
--------------------------------------------------------------------------------
/v2/protocol/gochan/sender.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package gochan
7 |
8 | import (
9 | "context"
10 | "errors"
11 | "fmt"
12 |
13 | "github.com/cloudevents/sdk-go/v2/binding"
14 | "github.com/cloudevents/sdk-go/v2/protocol"
15 | )
16 |
17 | // Sender implements Sender by sending Messages on a channel.
18 | type Sender chan<- binding.Message
19 |
20 | func (s Sender) Send(ctx context.Context, m binding.Message, transformers ...binding.Transformer) (err error) {
21 | if ctx == nil {
22 | return fmt.Errorf("nil Context")
23 | } else if m == nil {
24 | return fmt.Errorf("nil Message")
25 | }
26 |
27 | defer func() {
28 | err2 := m.Finish(err)
29 | if err == nil {
30 | err = err2
31 | }
32 | }()
33 | select {
34 | case <-ctx.Done():
35 | return ctx.Err()
36 | case s <- m:
37 | return nil
38 | }
39 | }
40 |
41 | func (s Sender) Close(ctx context.Context) (err error) {
42 | defer func() {
43 | if recover() != nil {
44 | err = errors.New("trying to close a closed Sender")
45 | }
46 | }()
47 | close(s)
48 | return nil
49 | }
50 |
51 | var _ protocol.SendCloser = (Sender)(nil)
52 |
--------------------------------------------------------------------------------
/v2/protocol/http/context.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package http
7 |
8 | import (
9 | "context"
10 |
11 | nethttp "net/http"
12 | "net/url"
13 | )
14 |
15 | type requestKey struct{}
16 |
17 | // RequestData holds the http.Request information subset that can be
18 | // used to retrieve HTTP information for an incoming CloudEvent.
19 | type RequestData struct {
20 | URL *url.URL
21 | Header nethttp.Header
22 | RemoteAddr string
23 | Host string
24 | }
25 |
26 | // WithRequestDataAtContext uses the http.Request to add RequestData
27 | // information to the Context.
28 | func WithRequestDataAtContext(ctx context.Context, r *nethttp.Request) context.Context {
29 | if r == nil {
30 | return ctx
31 | }
32 |
33 | return context.WithValue(ctx, requestKey{}, &RequestData{
34 | URL: r.URL,
35 | Header: r.Header,
36 | RemoteAddr: r.RemoteAddr,
37 | Host: r.Host,
38 | })
39 | }
40 |
41 | // RequestDataFromContext retrieves RequestData from the Context.
42 | // If not set nil is returned.
43 | func RequestDataFromContext(ctx context.Context) *RequestData {
44 | if req := ctx.Value(requestKey{}); req != nil {
45 | return req.(*RequestData)
46 | }
47 | return nil
48 | }
49 |
--------------------------------------------------------------------------------
/v2/protocol/http/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package http implements an HTTP binding using net/http module
8 | */
9 | package http
10 |
--------------------------------------------------------------------------------
/v2/protocol/http/headers.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package http
7 |
8 | import (
9 | "context"
10 | "github.com/cloudevents/sdk-go/v2/binding"
11 | "net/http"
12 | "net/textproto"
13 | "strings"
14 | "unicode"
15 |
16 | "github.com/cloudevents/sdk-go/v2/binding/spec"
17 | )
18 |
19 | var attributeHeadersMapping map[string]string
20 |
21 | type customHeaderKey int
22 |
23 | const (
24 | headerKey customHeaderKey = iota
25 | )
26 |
27 | func init() {
28 | attributeHeadersMapping = make(map[string]string)
29 | for _, v := range specs.Versions() {
30 | for _, a := range v.Attributes() {
31 | if a.Kind() == spec.DataContentType {
32 | attributeHeadersMapping[a.Name()] = ContentType
33 | } else {
34 | attributeHeadersMapping[a.Name()] = textproto.CanonicalMIMEHeaderKey(prefix + a.Name())
35 | }
36 | }
37 | }
38 | }
39 |
40 | func extNameToHeaderName(name string) string {
41 | var b strings.Builder
42 | b.Grow(len(name) + len(prefix))
43 | b.WriteString(prefix)
44 | b.WriteRune(unicode.ToUpper(rune(name[0])))
45 | b.WriteString(name[1:])
46 | return b.String()
47 | }
48 |
49 | func HeaderFrom(ctx context.Context) http.Header {
50 | return binding.GetOrDefaultFromCtx(ctx, headerKey, make(http.Header)).(http.Header)
51 | }
52 |
53 | func WithCustomHeader(ctx context.Context, header http.Header) context.Context {
54 | return context.WithValue(ctx, headerKey, header)
55 | }
56 |
--------------------------------------------------------------------------------
/v2/protocol/http/headers_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package http
7 |
8 | import (
9 | "context"
10 | "net/http"
11 | "reflect"
12 | "testing"
13 | )
14 |
15 | func TestHeaderFrom(t *testing.T) {
16 | type args struct {
17 | ctx context.Context
18 | }
19 | tests := []struct {
20 | name string
21 | args args
22 | want http.Header
23 | }{
24 | {
25 | name: "empty header",
26 | args: args{
27 | ctx: context.TODO(),
28 | },
29 | want: make(http.Header),
30 | },
31 | {
32 | name: "header with value",
33 | args: args{
34 | ctx: WithCustomHeader(context.TODO(), map[string][]string{"header": {"value"}}),
35 | },
36 | want: map[string][]string{"header": {"value"}},
37 | },
38 | }
39 | for _, tt := range tests {
40 | t.Run(tt.name, func(t *testing.T) {
41 | if got := HeaderFrom(tt.args.ctx); !reflect.DeepEqual(got, tt.want) {
42 | t.Errorf("HeaderFrom() = %v, want %v", got, tt.want)
43 | }
44 | })
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/v2/protocol/http/protocol_rate.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package http
7 |
8 | import (
9 | "context"
10 | "net/http"
11 | )
12 |
13 | type RateLimiter interface {
14 | // Allow attempts to take one token from the rate limiter for the specified
15 | // request. It returns ok when this operation was successful. In case ok is
16 | // false, reset will indicate the time in seconds when it is safe to perform
17 | // another attempt. An error is returned when this operation failed, e.g. due to
18 | // a backend error.
19 | Allow(ctx context.Context, r *http.Request) (ok bool, reset uint64, err error)
20 | // Close terminates rate limiter and cleans up any data structures or
21 | // connections that may remain open. After a store is stopped, Take() should
22 | // always return zero values.
23 | Close(ctx context.Context) error
24 | }
25 |
26 | type noOpLimiter struct{}
27 |
28 | func (n noOpLimiter) Allow(ctx context.Context, r *http.Request) (bool, uint64, error) {
29 | return true, 0, nil
30 | }
31 |
32 | func (n noOpLimiter) Close(ctx context.Context) error {
33 | return nil
34 | }
35 |
--------------------------------------------------------------------------------
/v2/protocol/http/result.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package http
7 |
8 | import (
9 | "errors"
10 | "fmt"
11 |
12 | "github.com/cloudevents/sdk-go/v2/protocol"
13 | )
14 |
15 | // NewResult returns a fully populated http Result that should be used as
16 | // a transport.Result.
17 | func NewResult(statusCode int, messageFmt string, args ...interface{}) protocol.Result {
18 | return &Result{
19 | StatusCode: statusCode,
20 | Format: messageFmt,
21 | Args: args,
22 | }
23 | }
24 |
25 | // Result wraps the fields required to make adjustments for http Responses.
26 | type Result struct {
27 | StatusCode int
28 | Format string
29 | Args []interface{}
30 | }
31 |
32 | // make sure Result implements error.
33 | var _ error = (*Result)(nil)
34 |
35 | // Is returns if the target error is a Result type checking target.
36 | func (e *Result) Is(target error) bool {
37 | if o, ok := target.(*Result); ok {
38 | return e.StatusCode == o.StatusCode
39 | }
40 |
41 | // Special case for nil == ACK
42 | if o, ok := target.(*protocol.Receipt); ok {
43 | if e == nil && o.ACK {
44 | return true
45 | }
46 | }
47 |
48 | // Allow for wrapped errors.
49 | if e != nil {
50 | err := fmt.Errorf(e.Format, e.Args...)
51 | return errors.Is(err, target)
52 | }
53 | return false
54 | }
55 |
56 | // Error returns the string that is formed by using the format string with the
57 | // provided args.
58 | func (e *Result) Error() string {
59 | return fmt.Sprintf("%d: %v", e.StatusCode, fmt.Errorf(e.Format, e.Args...))
60 | }
61 |
--------------------------------------------------------------------------------
/v2/protocol/lifecycle.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package protocol
7 |
8 | import (
9 | "context"
10 | )
11 |
12 | // Opener is the common interface for things that need to be opened.
13 | type Opener interface {
14 | // OpenInbound is a blocking call and ctx is used to stop the Inbound message Receiver/Responder.
15 | // Closing the context won't close the Receiver/Responder, aka it won't invoke Close(ctx).
16 | OpenInbound(ctx context.Context) error
17 | }
18 |
19 | // Closer is the common interface for things that can be closed.
20 | // After invoking Close(ctx), you cannot reuse the object you closed.
21 | type Closer interface {
22 | Close(ctx context.Context) error
23 | }
24 |
--------------------------------------------------------------------------------
/v2/protocol/outbound.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package protocol
7 |
8 | import (
9 | "context"
10 |
11 | "github.com/cloudevents/sdk-go/v2/binding"
12 | )
13 |
14 | // Sender sends messages.
15 | type Sender interface {
16 | // Send a message.
17 | //
18 | // Send returns when the "outbound" message has been sent. The Sender may
19 | // still be expecting acknowledgment or holding other state for the message.
20 | //
21 | // m.Finish() is called when sending is finished (both succeeded or failed):
22 | // expected acknowledgments (or errors) have been received, the Sender is
23 | // no longer holding any state for the message.
24 | // m.Finish() may be called during or after Send().
25 | //
26 | // transformers are applied when the message is written on the wire.
27 | Send(ctx context.Context, m binding.Message, transformers ...binding.Transformer) error
28 | }
29 |
30 | // SendCloser is a Sender that can be closed.
31 | type SendCloser interface {
32 | Sender
33 | Closer
34 | }
35 |
36 | // Requester sends a message and receives a response
37 | //
38 | // Optional interface that may be implemented by protocols that support
39 | // request/response correlation.
40 | type Requester interface {
41 | // Request sends m like Sender.Send() but also arranges to receive a response.
42 | Request(ctx context.Context, m binding.Message, transformers ...binding.Transformer) (binding.Message, error)
43 | }
44 |
45 | // RequesterCloser is a Requester that can be closed.
46 | type RequesterCloser interface {
47 | Requester
48 | Closer
49 | }
50 |
--------------------------------------------------------------------------------
/v2/protocol/test/benchmark.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package test
7 |
8 | import (
9 | "context"
10 | "testing"
11 |
12 | "github.com/stretchr/testify/assert"
13 | "golang.org/x/sync/errgroup"
14 |
15 | "github.com/cloudevents/sdk-go/v2/binding"
16 | "github.com/cloudevents/sdk-go/v2/protocol"
17 | "github.com/cloudevents/sdk-go/v2/test"
18 | )
19 |
20 | // BenchmarkSendReceive implements a simple send/receive benchmark.
21 | // Requires a sender and receiver that are connected to each other.
22 | func BenchmarkSendReceive(b *testing.B, s protocol.Sender, r protocol.Receiver) {
23 | e := test.FullEvent()
24 | m := (*binding.EventMessage)(&e)
25 | ctx := context.Background()
26 | b.ResetTimer() // Don't count setup.
27 | for i := 0; i < b.N; i++ {
28 | n := 10 // Messages to send async.
29 | g := errgroup.Group{}
30 | g.Go(func() error {
31 | for j := 0; j < n; j++ {
32 | if err := s.Send(ctx, m); err != nil {
33 | return err
34 | }
35 | }
36 | return nil
37 | })
38 | g.Go(func() error {
39 | for j := 0; j < n; j++ {
40 | m, err := r.Receive(ctx)
41 | if err != nil {
42 | return err
43 | }
44 | if err := m.Finish(nil); err != nil {
45 | return err
46 | }
47 | }
48 | return nil
49 | })
50 | assert.NoError(b, g.Wait())
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/v2/protocol/test/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package test
7 |
8 | /*
9 | Package test provides utilities to test binding implementations and transformers.
10 |
11 | */
12 |
--------------------------------------------------------------------------------
/v2/staticcheck.conf:
--------------------------------------------------------------------------------
1 | checks = [
2 | "all", "-ST1003",
3 | ]
--------------------------------------------------------------------------------
/v2/test/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | /*
7 | Package test has utilities (asserts, mocks, ...) to use cloudevents in your tests
8 | */
9 | package test
10 |
--------------------------------------------------------------------------------
/v2/test/event_asserts.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package test
7 |
8 | import (
9 | "testing"
10 |
11 | "github.com/cloudevents/sdk-go/v2/event"
12 | )
13 |
14 | // AssertEvent is a "matcher like" assertion method to test the properties of an event
15 | func AssertEvent(t testing.TB, have event.Event, matchers ...EventMatcher) {
16 | err := AllOf(matchers...)(have)
17 | if err != nil {
18 | t.Fatalf("Error while matching event: %s", err.Error())
19 | }
20 | }
21 |
22 | // AssertEventContextEquals asserts that two event.Event contexts are equals
23 | func AssertEventContextEquals(t testing.TB, want event.EventContext, have event.EventContext) {
24 | if err := IsContextEqualTo(want)(event.Event{Context: have}); err != nil {
25 | t.Fatalf("Error while matching event context: %s", err.Error())
26 | }
27 | }
28 |
29 | // AssertEventEquals asserts that two event.Event are equals
30 | func AssertEventEquals(t testing.TB, want event.Event, have event.Event) {
31 | if err := IsEqualTo(want)(have); err != nil {
32 | t.Fatalf("Error while matching event: %s", err.Error())
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/v2/types/allocate.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The CloudEvents Authors
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | package types
7 |
8 | import "reflect"
9 |
10 | // Allocate allocates a new instance of type t and returns:
11 | // asPtr is of type t if t is a pointer type and of type &t otherwise
12 | // asValue is a Value of type t pointing to the same data as asPtr
13 | func Allocate(obj interface{}) (asPtr interface{}, asValue reflect.Value) {
14 | if obj == nil {
15 | return nil, reflect.Value{}
16 | }
17 |
18 | switch t := reflect.TypeOf(obj); t.Kind() {
19 | case reflect.Ptr:
20 | reflectPtr := reflect.New(t.Elem())
21 | asPtr = reflectPtr.Interface()
22 | asValue = reflectPtr
23 | case reflect.Map:
24 | reflectPtr := reflect.MakeMap(t)
25 | asPtr = reflectPtr.Interface()
26 | asValue = reflectPtr
27 | case reflect.String:
28 | reflectPtr := reflect.New(t)
29 | asPtr = ""
30 | asValue = reflectPtr.Elem()
31 | case reflect.Slice:
32 | reflectPtr := reflect.MakeSlice(t, 0, 0)
33 | asPtr = reflectPtr.Interface()
34 | asValue = reflectPtr
35 | default:
36 | reflectPtr := reflect.New(t)
37 | asPtr = reflectPtr.Interface()
38 | asValue = reflectPtr.Elem()
39 | }
40 | return
41 | }
42 |
--------------------------------------------------------------------------------