├── .codecov.yml ├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── proposal.md │ └── question.md ├── pull_request_template.md ├── scripts │ └── get_release_version.py └── workflows │ └── build.yaml ├── .gitignore ├── CONTRIBUTING.md ├── Dapr.PluggableComponents.Complete.sln ├── Directory.Packages.props ├── LICENSE ├── NuGet.Config ├── README.md ├── assets └── logo-transparent.png ├── daprdocs └── content │ └── en │ └── dotnet-sdk-docs │ ├── _index.md │ ├── dotnet-advanced │ ├── _index.md │ ├── dotnet-application-environment.md │ ├── dotnet-component-lifetime.md │ └── dotnet-multiple-services.md │ ├── dotnet-bindings │ └── _index.md │ ├── dotnet-pub-sub │ └── _index.md │ └── dotnet-state-store │ └── _index.md ├── samples ├── AzureStorageQueuesPubSubSample │ ├── AzureStorageQueuesPubSub.cs │ ├── AzureStorageQueuesPubSubSample.csproj │ ├── Program.cs │ ├── README.md │ ├── appsettings.Development.json │ └── appsettings.json ├── Directory.Build.props ├── DiscordBindingSample │ ├── DiscordBinding.cs │ ├── DiscordBindingSample.csproj │ ├── Program.cs │ ├── README.md │ ├── appsettings.Development.json │ └── appsettings.json └── MemoryStateStoreSample │ ├── MemoryStateStoreSample.csproj │ ├── Program.cs │ ├── Services │ └── MemoryStateStore.cs │ ├── appsettings.Development.json │ └── appsettings.json └── src ├── Dapr.PluggableComponents.AspNetCore ├── Dapr.PluggableComponents.AspNetCore.csproj ├── DaprPluggableComponentsApplication.cs ├── DaprPluggableComponentsRegistry.cs ├── DaprPluggableComponentsServiceBuilder.cs ├── DaprPluggableComponentsServiceOptions.cs ├── IDaprPluggableComponentsRegistrar.cs ├── MultiplexedComponentProvider.cs ├── RegisteredComponentProvider.cs ├── Resources.Designer.cs ├── Resources.resx ├── WebApplicationBuilderExtensions.cs └── WebApplicationExtensions.cs ├── Dapr.PluggableComponents.Protos └── Dapr.PluggableComponents.Protos.csproj ├── Dapr.PluggableComponents.Tests ├── Adaptors │ ├── AdaptorFixture.cs │ ├── AsyncStreamReader.cs │ ├── InputBindingAdaptorTests.cs │ ├── OutputBindingAdaptorTests.cs │ ├── PubSubAdaptorTests.cs │ ├── StateStoreAdaptorTests.cs │ ├── TestServerCallContext.cs │ └── TransactionalStateStoreAdaptorTests.cs ├── AssemblyInfo.cs ├── Components │ ├── Bindings │ │ ├── InputBindingReadRequestTests.cs │ │ ├── InputBindingReadResponseTests.cs │ │ ├── MockCombinedBinding.cs │ │ ├── MockInputBinding.cs │ │ ├── MockOutputBinding.cs │ │ ├── OutputBindingInvokeRequestTests.cs │ │ └── OutputBindingInvokeResponseTests.cs │ ├── IMockPluggableComponent.cs │ ├── PubSub │ │ ├── MockPubSub.cs │ │ ├── PubSubPublishRequestTests.cs │ │ ├── PubSubPullMessagesResponseTests.cs │ │ └── PubSubPullMessagesTopicTests.cs │ └── StateStore │ │ ├── MockBulkStateStore.cs │ │ ├── MockQueryableStateStore.cs │ │ ├── MockStateStore.cs │ │ ├── MockTransactionalStateStore.cs │ │ ├── StateStoreBulkStateItemTests.cs │ │ ├── StateStoreDeleteRequestTests.cs │ │ ├── StateStoreGetRequestTests.cs │ │ ├── StateStoreGetResponseTests.cs │ │ ├── StateStoreQueryItemTests.cs │ │ ├── StateStoreQueryPaginationTests.cs │ │ ├── StateStoreQueryRequestTests.cs │ │ ├── StateStoreQueryResponseTests.cs │ │ ├── StateStoreQuerySortingTests.cs │ │ ├── StateStoreQueryTests.cs │ │ ├── StateStoreSetRequestTests.cs │ │ ├── StateStoreStateOptionsTests.cs │ │ ├── StateStoreTransactOperationTests.cs │ │ └── StateStoreTransactRequestTests.cs ├── ConversionAssert.cs ├── Dapr.PluggableComponents.Tests.csproj ├── DaprPluggableComponentsApplicationTests.cs ├── DaprPluggableComponentsServiceBuilderTests.cs ├── SocketFixture.cs ├── TestConstants.cs └── Unit.cs ├── Dapr.PluggableComponents.sln ├── Dapr.PluggableComponents ├── Adaptors │ ├── IDaprPluggableComponentProvider.cs │ ├── InputBindingAdaptor.cs │ ├── OutputBindingAdaptor.cs │ ├── PubSubAdaptor.cs │ ├── QueryableStateStoreAdaptor.cs │ ├── StateStoreAdaptor.cs │ └── TransactionalStateStoreAdaptor.cs ├── AssemblyInfo.cs ├── Components │ ├── Bindings │ │ ├── IInputBinding.cs │ │ ├── IOutputBinding.cs │ │ ├── InputBindingReadRequest.cs │ │ ├── InputBindingReadResponse.cs │ │ ├── OutputBindingInvokeRequest.cs │ │ └── OutputBindingInvokeResponse.cs │ ├── IPluggableComponent.cs │ ├── IPluggableComponentFeatures.cs │ ├── IPluggableComponentLiveness.cs │ ├── MessageDeliveryHandler.cs │ ├── MetadataRequest.cs │ ├── PubSub │ │ ├── IPubSub.cs │ │ ├── PubSubPublishRequest.cs │ │ ├── PubSubPullMessagesResponse.cs │ │ └── PubSubPullMessagesTopic.cs │ └── StateStore │ │ ├── BulkDeleteRowMismatchException.cs │ │ ├── ETagErrors.cs │ │ ├── ETagInvalidException.cs │ │ ├── ETagMismatchException.cs │ │ ├── IBulkStateStore.cs │ │ ├── IQueryableStateStore.cs │ │ ├── IStateStore.cs │ │ ├── ITransactionalStateStore.cs │ │ ├── StateStoreBulkStateItem.cs │ │ ├── StateStoreDeleteRequest.cs │ │ ├── StateStoreGetRequest.cs │ │ ├── StateStoreGetResponse.cs │ │ ├── StateStoreQuery.cs │ │ ├── StateStoreQueryItem.cs │ │ ├── StateStoreQueryPagination.cs │ │ ├── StateStoreQueryRequest.cs │ │ ├── StateStoreQueryResponse.cs │ │ ├── StateStoreQuerySorting.cs │ │ ├── StateStoreSetRequest.cs │ │ ├── StateStoreStateOptions.cs │ │ ├── StateStoreTransactOperation.cs │ │ └── StateStoreTransactRequest.cs ├── Constants.cs ├── Dapr.PluggableComponents.csproj ├── Resources.Designer.cs ├── Resources.resx └── Utilities │ └── MapFieldExtensions.cs ├── Directory.Build.props └── key.snk /.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | # basic 6 | target: auto 7 | threshold: 0% 8 | 9 | ignore: 10 | - "samples" # Samples 11 | - "src/Dapr.PluggableComponents.Tests" # Tests 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report a bug in the .NET Dapr Pluggable Components SDK 4 | title: '' 5 | labels: kind/bug 6 | assignees: '' 7 | 8 | --- 9 | ## Expected Behavior 10 | 11 | 12 | 13 | 14 | ## Actual Behavior 15 | 16 | 17 | 18 | 19 | ## Steps to Reproduce the Problem 20 | 21 | 22 | 23 | ## Release Note 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | RELEASE NOTE: 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/proposal.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Proposal 3 | about: Create a proposal for the .NET Dapr Pluggable Components SDK 4 | title: '' 5 | labels: kind/proposal 6 | assignees: '' 7 | 8 | --- 9 | ## Describe the proposal 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Ask a question about the .NET Dapr Pluggable Components SDK 4 | title: '' 5 | labels: kind/question 6 | assignees: '' 7 | 8 | --- 9 | ## Ask your question here 10 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | _Please explain the changes you've made_ 4 | 5 | ## Issue reference 6 | 7 | We strive to have all PR being opened based on an issue, where the problem or feature have been discussed prior to implementation. 8 | 9 | Please reference the issue this PR will close: #_[issue number]_ 10 | 11 | ## Checklist 12 | 13 | Please make sure you've completed the relevant tasks for this PR, out of the following list: 14 | 15 | * [ ] Code compiles correctly 16 | * [ ] Created/updated tests 17 | * [ ] Extended the documentation 18 | -------------------------------------------------------------------------------- /.github/scripts/get_release_version.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------ 2 | # Copyright 2023 The Dapr Authors 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | # ------------------------------------------------------------ 13 | 14 | # This script parses release version from Git tag and set the parsed version to 15 | # environment variable, REL_VERSION. 16 | 17 | import os 18 | import sys 19 | 20 | gitRef = os.getenv("GITHUB_REF") 21 | tagRefPrefix = "refs/tags/v" 22 | 23 | with open(os.getenv("GITHUB_ENV"), "a") as githubEnv: 24 | if gitRef is None or not gitRef.startswith(tagRefPrefix): 25 | githubEnv.write("REL_VERSION=edge\n") 26 | print ("This is daily build from {}...".format(gitRef)) 27 | sys.exit(0) 28 | 29 | releaseVersion = gitRef[len(tagRefPrefix):] 30 | releaseNotePath="docs/release_notes/v{}.md".format(releaseVersion) 31 | 32 | if gitRef.find("-rc.") > 0: 33 | print ("Release Candidate build from {}...".format(gitRef)) 34 | else: 35 | # Set LATEST_RELEASE to true 36 | githubEnv.write("LATEST_RELEASE=true\n") 37 | print ("Release build from {}...".format(gitRef)) 38 | 39 | githubEnv.write("REL_VERSION={}\n".format(releaseVersion)) 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Everything in the external/packages directory as nuget packages are restored here. 3 | /nuget/restored_packages/* 4 | 5 | # Build generated files in src 6 | /src/**/objd/**/* 7 | /src/**/obj/**/* 8 | /src/**/bin/**/* 9 | /src/**/gen/**/* 10 | /src/**/StyleCop.Cache 11 | 12 | # components generated by Dapr when run in samples project directory. 13 | /samples/**/components/*.yaml 14 | 15 | # launchSettings.json for samples and tests 16 | /samples/**/Properties/launchSettings.json 17 | /test/**/Properties/launchSettings.json 18 | 19 | # Test logs 20 | TestResults/ 21 | 22 | # MSBuild's log file 23 | msbuild.log 24 | 25 | # test results 26 | TestResults/ 27 | 28 | # Build.exe 29 | *.err 30 | *.wrn 31 | *.log 32 | *.prf 33 | *.trc 34 | *.nupkg 35 | buildd.dbb 36 | build.dbb 37 | buildd.evt 38 | build.evt 39 | 40 | ### 41 | Repository Bloat Risks 42 | ### 43 | *.exe 44 | *.dll 45 | *.lib 46 | *.pdb 47 | *.wim 48 | *.zip 49 | *.gz 50 | *.meta 51 | *.obj 52 | *.tmp 53 | *.tmp_proj 54 | *.log 55 | .builds 56 | 57 | ## Ignore Visual Studio temporary files, build results, and 58 | ## files generated by popular Visual Studio add-ons. 59 | **/.vs/**/* 60 | /test/**/v15/Server/sqlite3/**/* 61 | 62 | # User-specific files 63 | *.suo 64 | *.user 65 | *.userosscache 66 | *.sln.docstates 67 | 68 | # Build results 69 | [Dd]ebug/ 70 | [Dd]ebugPublic/ 71 | [Rr]elease/ 72 | [Rr]eleases/ 73 | x64/ 74 | x86/ 75 | build/ 76 | bld/ 77 | [Bb]in/ 78 | [Oo]bj/ 79 | 80 | #drop folder 81 | /src/drop/**/* 82 | 83 | # Roslyn cache directories 84 | *.ide/ 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | /drop 91 | 92 | # VS Code 93 | .vscode/ 94 | 95 | # Jetbrains 96 | .idea/ 97 | 98 | # coverlet code coverage results 99 | coverage.json 100 | .fake 101 | .ionide 102 | 103 | # Examples bloat 104 | examples/**/tmp -------------------------------------------------------------------------------- /Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /NuGet.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /assets/logo-transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dapr-sandbox/components-dotnet-sdk/ddba8197c78eba41ab4fb1be119867b0d334a0a1/assets/logo-transparent.png -------------------------------------------------------------------------------- /daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | type: docs 3 | title: "Advanced uses of the Dapr pluggable components .NET SDK" 4 | linkTitle: "Advanced" 5 | weight: 2000 6 | description: How to use advanced techniques with with the Dapr pluggable components .NET SDK 7 | is_preview: true 8 | --- 9 | 10 | While not typically needed by most, these guides show advanced ways to can configure your .NET pluggable components. -------------------------------------------------------------------------------- /daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/dotnet-component-lifetime.md: -------------------------------------------------------------------------------- 1 | --- 2 | type: docs 3 | title: "Lifetimes of .NET Dapr pluggable components" 4 | linkTitle: "Component lifetime" 5 | weight: 1000 6 | description: How to control the lifetime of a .NET pluggable component 7 | no_list: true 8 | is_preview: true 9 | --- 10 | 11 | There are two ways to register a component: 12 | 13 | - The component operates as a singleton, with lifetime managed by the SDK 14 | - A component's lifetime is determined by the pluggable component and can be multi-instance or a singleton, as needed 15 | 16 | ## Singleton components 17 | 18 | Components registered _by type_ are singletons: one instance will serve all configured components of that type associated with that socket. This approach is best when only a single component of that type exists and is shared amongst Dapr applications. 19 | 20 | ```csharp 21 | var app = DaprPluggableComponentsApplication.Create(); 22 | 23 | app.RegisterService( 24 | "service-a", 25 | serviceBuilder => 26 | { 27 | serviceBuilder.RegisterStateStore(); 28 | }); 29 | 30 | app.Run(); 31 | 32 | class SingletonStateStore : IStateStore 33 | { 34 | // ... 35 | } 36 | ``` 37 | 38 | ## Multi-instance components 39 | 40 | Components can be registered by passing a "factory method". This method will be called for each configured component of that type associated with that socket. The method returns the instance to associate with that component (whether shared or not). This approach is best when multiple components of the same type may be configured with different sets of metadata, when component operations need to be isolated from one another, etc. 41 | 42 | The factory method will be passed context, such as the ID of the configured Dapr component, that can be used to differentiate component instances. 43 | 44 | ```csharp 45 | var app = DaprPluggableComponentsApplication.Create(); 46 | 47 | app.RegisterService( 48 | "service-a", 49 | serviceBuilder => 50 | { 51 | serviceBuilder.RegisterStateStore( 52 | context => 53 | { 54 | return new MultiStateStore(context.InstanceId); 55 | }); 56 | }); 57 | 58 | app.Run(); 59 | 60 | class MultiStateStore : IStateStore 61 | { 62 | private readonly string instanceId; 63 | 64 | public MultiStateStore(string instanceId) 65 | { 66 | this.instanceId = instanceId; 67 | } 68 | 69 | // ... 70 | } 71 | ``` 72 | 73 | ## Next steps 74 | 75 | - [Learn more about the application environment]({{< ref "dotnet-application-environment" >}}) 76 | - [Learn more about multiple services]({{< ref "dotnet-multiple-services" >}}) 77 | - Learn more about using the Pluggable Component .NET SDK for: 78 | - [Bindings]({{< ref "dotnet-bindings" >}}) 79 | - [Pub/sub]({{< ref "dotnet-pub-sub" >}}) 80 | - [State store]({{< ref "dotnet-state-store" >}}) -------------------------------------------------------------------------------- /daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/dotnet-multiple-services.md: -------------------------------------------------------------------------------- 1 | --- 2 | type: docs 3 | title: "Multiple services in a .NET Dapr pluggable component" 4 | linkTitle: "Multiple services" 5 | weight: 1000 6 | description: How to expose multiple services from a .NET pluggable component 7 | no_list: true 8 | is_preview: true 9 | --- 10 | 11 | A pluggable component can host multiple components of varying types. You might do this: 12 | - To minimize the number of sidecars running in a cluster 13 | - To group related components that are likely to share libraries and implementation, such as: 14 | - A database exposed both as a general state store, and 15 | - Output bindings that allow more specific operations. 16 | 17 | Each Unix Domain Socket can manage calls to one component of each type. To host multiple components of the _same_ type, you can spread those types across multiple sockets. The SDK binds each socket to a "service", with each service composed of one or more component types. 18 | 19 | ## Registering multiple services 20 | 21 | Each call to `RegisterService()` binds a socket to a set of registered components, where one of each type of component can be registered per service. 22 | 23 | ```csharp 24 | var app = DaprPluggableComponentsApplication.Create(); 25 | 26 | app.RegisterService( 27 | "service-a", 28 | serviceBuilder => 29 | { 30 | serviceBuilder.RegisterStateStore(); 31 | serviceBuilder.RegisterBinding(); 32 | }); 33 | 34 | app.RegisterService( 35 | "service-b", 36 | serviceBuilder => 37 | { 38 | serviceBuilder.RegisterStateStore(); 39 | }); 40 | 41 | app.Run(); 42 | 43 | class MyDatabaseStateStore : IStateStore 44 | { 45 | // ... 46 | } 47 | 48 | class MyDatabaseOutputBinding : IOutputBinding 49 | { 50 | // ... 51 | } 52 | 53 | class AnotherStateStore : IStateStore 54 | { 55 | // ... 56 | } 57 | ``` 58 | 59 | ## Configuring Multiple Components 60 | 61 | Configuring Dapr to use the hosted components is the same as for any single component - the component YAML refers to the associated socket. 62 | 63 | ```yaml 64 | # 65 | # This component uses the state store associated with socket `state-store-a` 66 | # 67 | apiVersion: dapr.io/v1alpha1 68 | kind: Component 69 | metadata: 70 | name: state-store-a 71 | spec: 72 | type: state.service-a 73 | version: v1 74 | metadata: [] 75 | ``` 76 | 77 | ```yaml 78 | # 79 | # This component uses the state store associated with socket `state-store-b` 80 | # 81 | apiVersion: dapr.io/v1alpha1 82 | kind: Component 83 | metadata: 84 | name: state-store-b 85 | spec: 86 | type: state.service-b 87 | version: v1 88 | metadata: [] 89 | ``` 90 | 91 | ## Next steps 92 | 93 | - [Learn more about the component lifetime]({{< ref "dotnet-component-lifetime" >}}) 94 | - [Learn more about the application environment]({{< ref "dotnet-application-environment" >}}) 95 | - Learn more about using the Pluggable Component .NET SDK for: 96 | - [Bindings]({{< ref "dotnet-bindings" >}}) 97 | - [Pub/sub]({{< ref "dotnet-pub-sub" >}}) 98 | - [State store]({{< ref "dotnet-state-store" >}}) -------------------------------------------------------------------------------- /samples/AzureStorageQueuesPubSubSample/AzureStorageQueuesPubSubSample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /samples/AzureStorageQueuesPubSubSample/Program.cs: -------------------------------------------------------------------------------- 1 | using Dapr.PluggableComponents; 2 | 3 | var app = DaprPluggableComponentsApplication.Create(); 4 | 5 | app.RegisterService( 6 | "azure-storage-queues", 7 | serviceBuilder => 8 | { 9 | // Use this registration method to have a single pub-sub instance for all components. 10 | // serviceBuilder.RegisterPubSub(); 11 | 12 | // This registration method enables a pub-sub instance per component instance. 13 | serviceBuilder.RegisterPubSub( 14 | context => 15 | { 16 | Console.WriteLine("Creating pub-sub for instance '{0}' on socket '{1}'...", context.InstanceId, context.SocketPath); 17 | 18 | return new AzureStorageQueuesPubSub(context.ServiceProvider.GetRequiredService>()); 19 | }); 20 | }); 21 | 22 | app.Run(); 23 | -------------------------------------------------------------------------------- /samples/AzureStorageQueuesPubSubSample/README.md: -------------------------------------------------------------------------------- 1 | # Azure Storage Queues Pub-Sub Sample 2 | 3 | A Dapr Pluggable Component sample that allows applications to use Azure Storage Queues as a pub-sub component. 4 | 5 | ## Prerequisites 6 | 7 | 1. Create an Azure Storage resource for an Azure subscription in the Azure Portal. 8 | 1. Create a queue within the storage resource. 9 | 10 | ## Configuration 11 | 12 | An application that binds to the component should have a Pluggable Component configuration file that looks like the following: 13 | 14 | ```yaml 15 | apiVersion: dapr.io/v1alpha1 16 | kind: Component 17 | metadata: 18 | name: azure-storage-queues 19 | spec: 20 | type: pubsub.azure-storage-queues 21 | version: v1 22 | metadata: 23 | - name: connectionString 24 | value: "" 25 | - name: queueName 26 | value: "" 27 | - name: pollIntervalSeconds 28 | value: 29 | - name: maxMessages 30 | value: 31 | ``` 32 | 33 | The required metadata properties are ``, the connection string for the Azure Storage resource, and ``, the name of the queue to be polled for messages. The `pollIntervalSeconds` and `maxMessages` properties are optional. 34 | 35 | > NOTE: To prevent tokens from being mistakenly committed to a repro, it is best to use Dapr secrets components to store the connection string and then simply reference it from the binding component configuration. 36 | 37 | ## Application 38 | 39 | The application can publish messages to the queue, or subscribe to messages published to the queue, using [HTTP](https://docs.dapr.io/reference/api/pubsub_api/) or the [Dapr Client SDKs](https://docs.dapr.io/developing-applications/sdks/). -------------------------------------------------------------------------------- /samples/AzureStorageQueuesPubSubSample/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /samples/AzureStorageQueuesPubSubSample/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /samples/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /samples/DiscordBindingSample/DiscordBindingSample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /samples/DiscordBindingSample/Program.cs: -------------------------------------------------------------------------------- 1 | using Dapr.PluggableComponents; 2 | 3 | var app = DaprPluggableComponentsApplication.Create(); 4 | 5 | app.RegisterService( 6 | "discord-binding", 7 | serviceBuilder => 8 | { 9 | // Use this registration method to have a single binding instance for all components. 10 | // serviceBuilder.RegisterBinding(); 11 | 12 | // This registration method enables a binding instance per component instance. 13 | serviceBuilder.RegisterBinding( 14 | context => 15 | { 16 | Console.WriteLine("Creating binding for instance '{0}' on socket '{1}'...", context.InstanceId, context.SocketPath); 17 | 18 | return new DiscordBinding(context.ServiceProvider.GetRequiredService>()); 19 | }); 20 | }); 21 | 22 | app.Run(); 23 | -------------------------------------------------------------------------------- /samples/DiscordBindingSample/README.md: -------------------------------------------------------------------------------- 1 | # Discord Binding Sample 2 | 3 | A Dapr Pluggable Component sample that allows applications to bind to Discord and send and receive messages. 4 | 5 | ## Prerequisites 6 | 7 | ### Create a Discord Application and Bot 8 | 9 | The bindings in this sample are exposed within Discord as an "application bot". This README will not replicate the comprehensive Discord documentation for creation of a bot available [here](https://discord.com/developers/docs/intro). 10 | 11 | ### Create a Discord Test Server 12 | 13 | It is recommended that developers test application bots on a test (i.e. personal) Discord server; specific instructions are [here](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server-). 14 | 15 | ### Install the Application Bot on the Test Server 16 | 17 | You can use the Discord Developer Portal's OAuth2::URL Generator to generate a URL that installs the application bot on the test server. More instructions are [here](),https://discord.com/developers/docs/getting-started#installing-your-app. 18 | 19 | > NOTE: This sample requires the bot to have the `bot` scope and `Read Messages/View Channels` and `Send Messages` bot permissions on any associated server. 20 | 21 | ## Configuration 22 | 23 | An application that binds to the component should have a Pluggable Component configuration file that looks like the following: 24 | 25 | ```yaml 26 | apiVersion: dapr.io/v1alpha1 27 | kind: Component 28 | metadata: 29 | name: discord-binding 30 | spec: 31 | type: bindings.discord-binding 32 | version: v1 33 | metadata: 34 | - name: token 35 | value: "" 36 | ``` 37 | 38 | > NOTE: To prevent tokens from being mistakenly committed to a repro, it is best to use Dapr secrets components to store the token and then simply reference it from the binding component configuration. 39 | 40 | ## Application 41 | 42 | The application can send messages to Discord, using HTTP or the Dapr Client SDK, by invoking the `SendMessage` operation of the output binding with JSON data: 43 | 44 | ```json 45 | { 46 | "channelId": "", 47 | "content": "" 48 | } 49 | ``` 50 | 51 | An example HTTP request would look like: 52 | 53 | `POST http://localhost:/v1.0/bindings/discord-binding` 54 | 55 | ```json 56 | { 57 | "data": { 58 | "channelId": "1234567890123456789", 59 | "content": "Hello world from Dapr!" 60 | }, 61 | "operation": "SendMessage" 62 | } 63 | ``` 64 | 65 | >NOTE: The channel ID can be found by [enabling developer mode](https://discord.com/developers/docs/game-sdk/store#application-test-mode) in Discord, right-clicking the channel name, and selecting `Copy ID` from the context menu. 66 | 67 | The application can read messages sent to Discord by exposing a `POST` route that matches the binding name (i.e. `discord-binding`), and accepts a JSON body of the form: 68 | 69 | ```json 70 | { 71 | "channelId": "", 72 | "content": "" 73 | } 74 | ``` 75 | -------------------------------------------------------------------------------- /samples/DiscordBindingSample/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /samples/DiscordBindingSample/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /samples/MemoryStateStoreSample/MemoryStateStoreSample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /samples/MemoryStateStoreSample/Program.cs: -------------------------------------------------------------------------------- 1 | using MemoryStateStoreSample.Services; 2 | 3 | var app = DaprPluggableComponentsApplication.Create(); 4 | 5 | app.RegisterService( 6 | "memstore", 7 | serviceBuilder => 8 | { 9 | // Use this registration method to have a single state store instance for all components. 10 | // serviceBuilder.RegisterStateStore(); 11 | 12 | // This registration method enables a state store instance per component instance. 13 | serviceBuilder.RegisterStateStore( 14 | context => 15 | { 16 | Console.WriteLine("Creating state store for instance '{0}' on socket '{1}'...", context.InstanceId, context.SocketPath); 17 | 18 | return new MemoryStateStore(context.ServiceProvider.GetRequiredService>()); 19 | }); 20 | }); 21 | 22 | app.Run(); 23 | -------------------------------------------------------------------------------- /samples/MemoryStateStoreSample/Services/MemoryStateStore.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.Text; 3 | using Dapr.PluggableComponents.Components; 4 | 5 | namespace MemoryStateStoreSample.Services; 6 | 7 | internal sealed class MemoryStateStore : IStateStore 8 | { 9 | private readonly ILogger logger; 10 | 11 | private readonly IDictionary storage = new ConcurrentDictionary(); 12 | 13 | public MemoryStateStore(ILogger logger) 14 | { 15 | this.logger = logger; 16 | } 17 | 18 | #region IStateStore Members 19 | 20 | public Task DeleteAsync(StateStoreDeleteRequest request, CancellationToken cancellationToken = default) 21 | { 22 | this.logger.LogInformation("Delete request for key {key}", request.Key); 23 | 24 | this.storage.Remove(request.Key); 25 | 26 | return Task.CompletedTask; 27 | } 28 | 29 | public Task GetAsync(StateStoreGetRequest request, CancellationToken cancellationToken = default) 30 | { 31 | this.logger.LogInformation("Get request for key {key}", request.Key); 32 | 33 | StateStoreGetResponse? response = null; 34 | 35 | if (this.storage.TryGetValue(request.Key, out var data)) 36 | { 37 | response = new StateStoreGetResponse 38 | { 39 | Data = Encoding.UTF8.GetBytes(data) 40 | }; 41 | } 42 | 43 | return Task.FromResult(response); 44 | } 45 | 46 | public Task InitAsync(MetadataRequest request, CancellationToken cancellationToken = default) 47 | { 48 | return Task.CompletedTask; 49 | } 50 | 51 | public Task SetAsync(StateStoreSetRequest request, CancellationToken cancellationToken = default) 52 | { 53 | this.logger.LogInformation("Set request for key {key}", request.Key); 54 | 55 | this.storage[request.Key] = Encoding.UTF8.GetString(request.Value.Span); 56 | 57 | return Task.CompletedTask; 58 | } 59 | 60 | #endregion 61 | } 62 | -------------------------------------------------------------------------------- /samples/MemoryStateStoreSample/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /samples/MemoryStateStoreSample/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.AspNetCore/Dapr.PluggableComponents.AspNetCore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | This package contains the reference assemblies for hosting pluggable components for Dapr. 9 | $(PackageTags); 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | True 29 | True 30 | Resources.resx 31 | 32 | 33 | 34 | 35 | 36 | ResXFileCodeGenerator 37 | Resources.Designer.cs 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceOptions.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents; 15 | 16 | /// 17 | /// Represents options related to the socket file associated with a service. 18 | /// 19 | /// Gets or sets the name of the socket. 20 | public sealed record DaprPluggableComponentsServiceOptions(string SocketName) 21 | { 22 | /// 23 | /// Gets or sets the extension added to the socket file name. 24 | /// 25 | /// 26 | /// If omitted and not specified by the environment 27 | /// variable, the default extension will be used. 28 | /// 29 | public string? SocketExtension { get; init; } 30 | 31 | /// 32 | /// Gets or sets the folder in which the socket file is created. 33 | /// 34 | /// 35 | /// If omitted and not specified by the environment 36 | /// variable, the default folder will be used. 37 | /// 38 | public string? SocketFolder { get; init; } 39 | } 40 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.AspNetCore/IDaprPluggableComponentsRegistrar.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents; 15 | 16 | internal interface IDaprPluggableComponentsRegistrar 17 | { 18 | void RegisterAdaptor() where TAdaptor : class; 19 | 20 | void RegisterComponent(string socketPath) where TComponent : class; 21 | 22 | void RegisterComponent(string socketPath, ComponentProviderDelegate componentFactory) where TComponent : class; 23 | 24 | void RegisterProvider(string socketPath) 25 | where TComponent : class 26 | where TComponentImpl : class; 27 | } 28 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.AspNetCore/MultiplexedComponentProvider.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using System.Collections.Concurrent; 15 | using Dapr.PluggableComponents.Adaptors; 16 | using Grpc.Core; 17 | 18 | namespace Dapr.PluggableComponents; 19 | 20 | internal sealed class MultiplexedComponentProvider : IDaprPluggableComponentProvider 21 | { 22 | private const string MetadataInstanceId = "x-component-instance"; 23 | 24 | private readonly ComponentProviderDelegate componentProvider; 25 | private readonly ConcurrentDictionary> components = new ConcurrentDictionary>(); 26 | private readonly Lazy defaultComponent; 27 | private readonly ComponentProviderContext defaultComponentProviderContext; 28 | 29 | public MultiplexedComponentProvider(ComponentProviderDelegate componentProvider, IServiceProvider serviceProvider, string socketPath) 30 | { 31 | this.componentProvider = componentProvider ?? throw new ArgumentNullException(nameof(componentProvider)); 32 | 33 | this.defaultComponentProviderContext = new ComponentProviderContext( 34 | null, 35 | serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)), 36 | socketPath ?? throw new ArgumentNullException(nameof(socketPath))); 37 | 38 | this.defaultComponent = new Lazy(() => componentProvider(this.defaultComponentProviderContext)); 39 | } 40 | 41 | #region IDaprPluggableComponentProvider Members 42 | 43 | public T GetComponent(ServerCallContext context) 44 | { 45 | var entry = context.RequestHeaders.Get(MetadataInstanceId); 46 | 47 | var component = 48 | entry != null 49 | ? this.components.GetOrAdd(entry.Value, instanceId => new Lazy(() => this.componentProvider(this.defaultComponentProviderContext with { InstanceId = instanceId }))) 50 | : this.defaultComponent; 51 | 52 | return component.Value; 53 | } 54 | 55 | #endregion 56 | } 57 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.AspNetCore/RegisteredComponentProvider.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using System.Globalization; 15 | using Dapr.PluggableComponents.Adaptors; 16 | using Dapr.PluggableComponents.AspNetCore; 17 | using Grpc.Core; 18 | using Microsoft.AspNetCore.Connections.Features; 19 | 20 | namespace Dapr.PluggableComponents; 21 | 22 | internal sealed class RegisteredComponentProvider : IDaprPluggableComponentProvider 23 | { 24 | private readonly DaprPluggableComponentsRegistry registry; 25 | private readonly IServiceProvider serviceProvider; 26 | 27 | public RegisteredComponentProvider(DaprPluggableComponentsRegistry registry, IServiceProvider serviceProvider) 28 | { 29 | ArgumentNullException.ThrowIfNull(registry); 30 | ArgumentNullException.ThrowIfNull(serviceProvider); 31 | 32 | this.registry = registry; 33 | this.serviceProvider = serviceProvider; 34 | } 35 | 36 | public TComponent GetComponent(ServerCallContext context) 37 | { 38 | string socketPath = GetSocketPath(context); 39 | 40 | var componentProvider = this.registry.GetComponentProvider(this.serviceProvider, socketPath) 41 | ?? throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Resources.RegisteredComponentProviderNoProviderMessage, typeof(TComponent))); 42 | 43 | return componentProvider.GetComponent(context); 44 | } 45 | 46 | private static string GetSocketPath(ServerCallContext context) 47 | { 48 | var httpContext = context.GetHttpContext(); 49 | var socketFeature = httpContext.Features.Get(); 50 | var socketPath = socketFeature?.Socket.LocalEndPoint?.ToString() ?? throw new InvalidOperationException(Resources.RegisteredComponentProviderUnknownSocketMessage); 51 | 52 | return socketPath; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.AspNetCore/WebApplicationExtensions.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Microsoft.AspNetCore.Builder; 15 | using Microsoft.AspNetCore.Routing; 16 | 17 | namespace Dapr.PluggableComponents; 18 | 19 | /// 20 | /// Represents extension methods for registering Dapr Pluggable Component related services with instances. 21 | /// 22 | public static class WebApplicationExtensions 23 | { 24 | /// 25 | /// Maps services needed to host Dapr Pluggable Components via an ASP.NET application. 26 | /// 27 | /// The type of ASP.NET endpoint builder. 28 | /// An ASP.NET endpoint builder. 29 | /// The current builder instance. 30 | public static TBuilder MapDaprPluggableComponentsSupportServices(this TBuilder app) 31 | where TBuilder : IEndpointRouteBuilder 32 | { 33 | // Dapr component discovery relies on the gRPC reflection service. 34 | app.MapGrpcReflectionService(); 35 | 36 | return app; 37 | } 38 | 39 | /// 40 | /// Maps a gRPC "adaptor" service through which Dapr Pluggable Component calls are made. 41 | /// 42 | /// The type of gRPC service. 43 | /// An ASP.NET endpoint builder. 44 | /// A through which the service can be further configured. 45 | public static GrpcServiceEndpointConventionBuilder MapDaprPluggableComponentAdaptor(this IEndpointRouteBuilder app) 46 | where T : class 47 | { 48 | return app.MapGrpcService(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Protos/Dapr.PluggableComponents.Protos.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | v1 5 | v1.11.0 6 | https://raw.githubusercontent.com/dapr/dapr/$(ProtosTag)/dapr/proto/components/$(ProtosVersion) 7 | $(BaseIntermediateOutputPath)$(Configuration)\$(TargetFramework)\Protos 8 | $(ProtosRootDir)\dapr\proto\components\$(ProtosVersion) 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | This package contains the gRPC generated types for developing pluggable components for Dapr. 21 | $(PackageTags); 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | runtime; build; native; contentfiles; analyzers; buildtransitive 34 | all 35 | 36 | 37 | 38 | 39 | 41 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Adaptors/AsyncStreamReader.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using System.Threading.Channels; 15 | using Grpc.Core; 16 | 17 | namespace Dapr.PluggableComponents.Adaptors; 18 | 19 | internal sealed class AsyncStreamReader : IAsyncStreamReader 20 | where TRequest : class 21 | { 22 | private readonly Channel channel = Channel.CreateUnbounded(); 23 | private TRequest? current; 24 | 25 | public ValueTask AddAsync(TRequest request, CancellationToken cancellationToken = default) 26 | { 27 | return this.channel.Writer.WriteAsync(request, cancellationToken); 28 | } 29 | 30 | public void Complete() 31 | { 32 | this.channel.Writer.Complete(); 33 | } 34 | 35 | #region IAsyncStreamReader Members 36 | 37 | public TRequest Current => this.current ?? throw new InvalidOperationException(); 38 | 39 | public async Task MoveNext(CancellationToken cancellationToken) 40 | { 41 | var result = await this.channel.Reader.WaitToReadAsync(cancellationToken); 42 | 43 | if (result && this.channel.Reader.TryRead(out this.current)) 44 | { 45 | return true; 46 | } 47 | 48 | this.current = null; 49 | 50 | return false; 51 | } 52 | 53 | #endregion 54 | } 55 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Adaptors/OutputBindingAdaptorTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.Client.Autogen.Grpc.v1; 15 | using Dapr.PluggableComponents.Components.Bindings; 16 | using Dapr.Proto.Components.V1; 17 | using NSubstitute; 18 | using Xunit; 19 | 20 | namespace Dapr.PluggableComponents.Adaptors; 21 | 22 | public sealed class OutputBindignAdaptorTests 23 | { 24 | [Fact] 25 | public Task InitTests() 26 | { 27 | return AdaptorFixture.TestInitAsync( 28 | () => AdaptorFixture.CreateOutputBinding(), 29 | (fixture, metadataRequest) => fixture.Adaptor.Init(new Proto.Components.V1.OutputBindingInitRequest { Metadata = metadataRequest }, fixture.Context)); 30 | } 31 | 32 | [Fact] 33 | public Task PingTests() 34 | { 35 | return AdaptorFixture.TestPingAsync( 36 | AdaptorFixture.CreateOutputBinding, 37 | fixture => fixture.Adaptor.Ping(new PingRequest(), fixture.Context)); 38 | } 39 | 40 | [Fact] 41 | public async Task InvokeTests() 42 | { 43 | using var fixture = AdaptorFixture.CreateOutputBinding(); 44 | 45 | string operation = "operation"; 46 | string contentType = "application/json"; 47 | 48 | var request = new InvokeRequest { Operation = operation }; 49 | 50 | fixture.MockComponent 51 | .InvokeAsync(Arg.Is(request => request.Operation == operation), Arg.Is(token => token == fixture.Context.CancellationToken)) 52 | .Returns(new OutputBindingInvokeResponse { ContentType = contentType }); 53 | 54 | var response = await fixture.Adaptor.Invoke(new InvokeRequest { Operation = operation }, fixture.Context); 55 | 56 | Assert.Equal(contentType, response.ContentType); 57 | 58 | await fixture.MockComponent 59 | .Received(1) 60 | .InvokeAsync(Arg.Is(request => request.Operation == operation), Arg.Is(token => token == fixture.Context.CancellationToken)); 61 | } 62 | 63 | [Fact] 64 | public async Task ListOperationsTests() 65 | { 66 | using var fixture = AdaptorFixture.CreateOutputBinding(); 67 | 68 | var operations = new[] { "operation1", "operation2" }; 69 | 70 | fixture.MockComponent 71 | .ListOperationsAsync(Arg.Is(token => token == fixture.Context.CancellationToken)) 72 | .Returns(operations); 73 | 74 | var response = await fixture.Adaptor.ListOperations(new ListOperationsRequest(), fixture.Context); 75 | 76 | Assert.Equal(operations, response.Operations); 77 | 78 | await fixture.MockComponent 79 | .Received(1) 80 | .ListOperationsAsync(Arg.Is(token => token == fixture.Context.CancellationToken)); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Adaptors/TestServerCallContext.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Grpc.Core; 15 | 16 | namespace Dapr.PluggableComponents.Adaptors; 17 | 18 | internal sealed class TestServerCallContext : ServerCallContext, IDisposable 19 | { 20 | private readonly CancellationTokenSource cts = new CancellationTokenSource(); 21 | 22 | public void Cancel() 23 | { 24 | this.cts.Cancel(); 25 | } 26 | 27 | #region ServerCallContext Overrides 28 | 29 | protected override string MethodCore => throw new NotImplementedException(); 30 | 31 | protected override string HostCore => throw new NotImplementedException(); 32 | 33 | protected override string PeerCore => throw new NotImplementedException(); 34 | 35 | protected override DateTime DeadlineCore => throw new NotImplementedException(); 36 | 37 | protected override Metadata RequestHeadersCore => throw new NotImplementedException(); 38 | 39 | protected override CancellationToken CancellationTokenCore => this.cts.Token; 40 | 41 | protected override Metadata ResponseTrailersCore => throw new NotImplementedException(); 42 | 43 | protected override Status StatusCore { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } 44 | 45 | protected override WriteOptions? WriteOptionsCore { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } 46 | 47 | protected override AuthContext AuthContextCore => throw new NotImplementedException(); 48 | 49 | protected override ContextPropagationToken CreatePropagationTokenCore(ContextPropagationOptions? options) 50 | { 51 | throw new NotImplementedException(); 52 | } 53 | 54 | protected override Task WriteResponseHeadersAsyncCore(Metadata responseHeaders) 55 | { 56 | throw new NotImplementedException(); 57 | } 58 | 59 | #endregion 60 | 61 | #region IDisposable Members 62 | 63 | public void Dispose() 64 | { 65 | this.cts.Dispose(); 66 | } 67 | 68 | #endregion 69 | } 70 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Adaptors/TransactionalStateStoreAdaptorTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.PluggableComponents.Adaptors; 15 | using Dapr.Proto.Components.V1; 16 | using Grpc.Core; 17 | using Microsoft.Extensions.Logging; 18 | using NSubstitute; 19 | using Xunit; 20 | 21 | namespace Dapr.PluggableComponents.Components.StateStore; 22 | 23 | public sealed class TransactionalStateStoreAdaptorTests 24 | { 25 | [Fact] 26 | public async Task TransactTest() 27 | { 28 | var mockStateStore = Substitute.For(); 29 | 30 | mockStateStore 31 | .TransactAsync(Arg.Any(), Arg.Any()) 32 | .Returns(Task.CompletedTask); 33 | 34 | var logger = Substitute.For>(); 35 | 36 | var mockComponentProvider = Substitute.For>(); 37 | 38 | mockComponentProvider 39 | .GetComponent(Arg.Any()) 40 | .Returns(mockStateStore); 41 | 42 | var adaptor = new TransactionalStateStoreAdaptor(logger, mockComponentProvider); 43 | 44 | using var context = new TestServerCallContext(); 45 | 46 | var grpcRequest = new TransactionalStateRequest(); 47 | 48 | grpcRequest.Metadata.Add("key", "value"); 49 | 50 | await adaptor.Transact(grpcRequest, context); 51 | 52 | await mockStateStore 53 | .Received(1) 54 | .TransactAsync(Arg.Is(request => AssertMetadataEqual(grpcRequest.Metadata, request.Metadata)), Arg.Is(cancellationToken => cancellationToken == context.CancellationToken)); 55 | } 56 | 57 | private static bool AssertMetadataEqual(IReadOnlyDictionary expected, IReadOnlyDictionary actual) 58 | { 59 | Assert.Equal(expected, actual); 60 | 61 | return true; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using System.Runtime.CompilerServices; 15 | 16 | [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] 17 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/Bindings/InputBindingReadRequestTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.Proto.Components.V1; 15 | using Google.Protobuf; 16 | using Xunit; 17 | 18 | namespace Dapr.PluggableComponents.Components.Bindings; 19 | 20 | public sealed class InputBindingReadRequestTests 21 | { 22 | [Fact] 23 | public void FromReadRequestTests() 24 | { 25 | ConversionAssert.StringEqual( 26 | messageId => new ReadRequest { MessageId = messageId }, 27 | InputBindingReadRequest.FromReadRequest, 28 | request => request.MessageId); 29 | 30 | ConversionAssert.DataEqual( 31 | responseData => new ReadRequest { ResponseData = ByteString.CopyFrom(responseData) }, 32 | InputBindingReadRequest.FromReadRequest, 33 | request => request.ResponseData.Span.ToArray()); 34 | 35 | ConversionAssert.Equal( 36 | responseError => new ReadRequest { ResponseError = responseError }, 37 | (_, request) => InputBindingReadRequest.FromReadRequest(request), 38 | request => request.ResponseErrorMessage, 39 | new (AckResponseError?, string?)[] 40 | { 41 | (null, null), 42 | (new AckResponseError(), ""), 43 | (new AckResponseError { Message = "" }, ""), 44 | (new AckResponseError { Message = "message" }, "message") 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/Bindings/InputBindingReadResponseTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Xunit; 15 | 16 | namespace Dapr.PluggableComponents.Components.Bindings; 17 | 18 | public sealed class InputBindingReadResponseTests 19 | { 20 | [Fact] 21 | public void ToReadResponseTests() 22 | { 23 | ConversionAssert.ContentTypeEqual( 24 | contentType => new InputBindingReadResponse { ContentType = contentType }, 25 | response => InputBindingReadResponse.ToReadResponse("messageId", response), 26 | response => response.ContentType); 27 | 28 | ConversionAssert.DataEqual( 29 | data => new InputBindingReadResponse { Data = data }, 30 | response => InputBindingReadResponse.ToReadResponse("messageId", response), 31 | response => response.Data.Span.ToArray()); 32 | 33 | ConversionAssert.StringEqual( 34 | messageId => new InputBindingReadResponse(), 35 | (messageId, response) => InputBindingReadResponse.ToReadResponse(messageId, response), 36 | response => response.MessageId); 37 | 38 | ConversionAssert.MetadataEqual( 39 | metadata => new InputBindingReadResponse { Metadata = metadata }, 40 | response => InputBindingReadResponse.ToReadResponse("messageId", response), 41 | response => response.Metadata); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/Bindings/MockCombinedBinding.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components.Bindings; 15 | 16 | internal interface IMockCombinedBinding : IMockPluggableComponent, IInputBinding, IOutputBinding where T : class 17 | { 18 | } 19 | 20 | internal sealed class MockCombinedBinding : IInputBinding, IOutputBinding where T : class 21 | { 22 | private readonly IMockCombinedBinding proxy; 23 | 24 | public MockCombinedBinding(IMockCombinedBinding proxy) 25 | { 26 | this.proxy = proxy; 27 | 28 | this.proxy.Create(); 29 | } 30 | 31 | #region IPluggableComponent Members 32 | 33 | public Task InitAsync(MetadataRequest request, CancellationToken cancellationToken = default) 34 | { 35 | return this.proxy.InitAsync(request, cancellationToken); 36 | } 37 | 38 | #endregion 39 | 40 | #region IInputBinding Members 41 | 42 | public Task ReadAsync(MessageDeliveryHandler deliveryHandler, CancellationToken cancellationToken = default) 43 | { 44 | return this.proxy.ReadAsync(deliveryHandler, cancellationToken); 45 | } 46 | 47 | #endregion 48 | 49 | #region IOutputBinding Members 50 | 51 | public Task InvokeAsync(OutputBindingInvokeRequest request, CancellationToken cancellationToken = default) 52 | { 53 | return this.proxy.InvokeAsync(request, cancellationToken); 54 | } 55 | 56 | public Task ListOperationsAsync(CancellationToken cancellationToken = default) 57 | { 58 | return this.proxy.ListOperationsAsync(cancellationToken); 59 | } 60 | 61 | #endregion 62 | } 63 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/Bindings/MockInputBinding.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components.Bindings; 15 | 16 | internal interface IMockInputBinding : IMockPluggableComponent, IInputBinding where T : class 17 | { 18 | } 19 | 20 | internal sealed class MockInputBinding : IInputBinding where T : class 21 | { 22 | private readonly IMockInputBinding proxy; 23 | 24 | public MockInputBinding(IMockInputBinding proxy) 25 | { 26 | this.proxy = proxy; 27 | 28 | this.proxy.Create(); 29 | } 30 | 31 | #region IInputBinding Members 32 | 33 | public Task InitAsync(MetadataRequest request, CancellationToken cancellationToken = default) 34 | { 35 | return this.proxy.InitAsync(request, cancellationToken); 36 | } 37 | 38 | public Task ReadAsync(MessageDeliveryHandler deliveryHandler, CancellationToken cancellationToken = default) 39 | { 40 | return this.proxy.ReadAsync(deliveryHandler, cancellationToken); 41 | } 42 | 43 | #endregion 44 | } 45 | 46 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/Bindings/MockOutputBinding.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components.Bindings; 15 | 16 | internal interface IMockOutputBinding : IMockPluggableComponent, IOutputBinding where T : class 17 | { 18 | } 19 | 20 | internal sealed class MockOutputBinding : IOutputBinding where T : class 21 | { 22 | private readonly IMockOutputBinding proxy; 23 | 24 | public MockOutputBinding(IMockOutputBinding proxy) 25 | { 26 | this.proxy = proxy; 27 | 28 | this.proxy.Create(); 29 | } 30 | 31 | #region IOutputBinding Members 32 | 33 | public Task InitAsync(MetadataRequest request, CancellationToken cancellationToken = default) 34 | { 35 | return this.proxy.InitAsync(request, cancellationToken); 36 | } 37 | 38 | public Task InvokeAsync(OutputBindingInvokeRequest request, CancellationToken cancellationToken = default) 39 | { 40 | return this.proxy.InvokeAsync(request, cancellationToken); 41 | } 42 | 43 | public Task ListOperationsAsync(CancellationToken cancellationToken = default) 44 | { 45 | return this.proxy.ListOperationsAsync(cancellationToken); 46 | } 47 | 48 | #endregion 49 | } 50 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/Bindings/OutputBindingInvokeRequestTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.PluggableComponents.Utilities; 15 | using Dapr.Proto.Components.V1; 16 | using Google.Protobuf; 17 | using Xunit; 18 | 19 | namespace Dapr.PluggableComponents.Components.Bindings; 20 | 21 | public sealed class OutputBindingInvokeRequestTests 22 | { 23 | [Fact] 24 | public void FromInvokeRequestTests() 25 | { 26 | ConversionAssert.DataEqual( 27 | data => new InvokeRequest { Data = ByteString.CopyFrom(data) }, 28 | OutputBindingInvokeRequest.FromInvokeRequest, 29 | request => request.Data.Span.ToArray()); 30 | 31 | ConversionAssert.MetadataEqual( 32 | metadata => 33 | { 34 | var request = new InvokeRequest(); 35 | 36 | request.Metadata.Add(metadata); 37 | 38 | return request; 39 | }, 40 | OutputBindingInvokeRequest.FromInvokeRequest, 41 | request => request.Metadata); 42 | 43 | ConversionAssert.StringEqual( 44 | operation => new InvokeRequest { Operation = operation }, 45 | OutputBindingInvokeRequest.FromInvokeRequest, 46 | request => request.Operation); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/Bindings/OutputBindingInvokeResponseTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Xunit; 15 | 16 | namespace Dapr.PluggableComponents.Components.Bindings; 17 | 18 | public sealed class OutputBindingInvokeResponseTests 19 | { 20 | [Fact] 21 | public void ToInvokeResponseTests() 22 | { 23 | ConversionAssert.ContentTypeEqual( 24 | contentType => new OutputBindingInvokeResponse { ContentType = contentType }, 25 | response => OutputBindingInvokeResponse.ToInvokeResponse(response), 26 | response => response.ContentType); 27 | 28 | ConversionAssert.DataEqual( 29 | data => new OutputBindingInvokeResponse { Data = data }, 30 | response => OutputBindingInvokeResponse.ToInvokeResponse(response), 31 | response => response.Data.Span.ToArray()); 32 | 33 | ConversionAssert.MetadataEqual( 34 | metadata => new OutputBindingInvokeResponse { Metadata = metadata }, 35 | response => OutputBindingInvokeResponse.ToInvokeResponse(response), 36 | response => response.Metadata); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/IMockPluggableComponent.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components; 15 | 16 | internal interface IMockPluggableComponent : IPluggableComponent 17 | { 18 | void Create(); 19 | } 20 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/PubSub/MockPubSub.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components.PubSub; 15 | 16 | internal interface IMockPubSub : IMockPluggableComponent, IPubSub where T : class 17 | { 18 | } 19 | 20 | internal sealed class MockPubSub : IPubSub where T : class 21 | { 22 | private readonly IMockPubSub proxy; 23 | 24 | public MockPubSub(IMockPubSub proxy) 25 | { 26 | this.proxy = proxy; 27 | 28 | this.proxy.Create(); 29 | } 30 | 31 | #region IPubSub Members 32 | 33 | public Task InitAsync(MetadataRequest request, CancellationToken cancellationToken = default) 34 | { 35 | return this.proxy.InitAsync(request, cancellationToken); 36 | } 37 | 38 | public Task PublishAsync(PubSubPublishRequest request, CancellationToken cancellationToken = default) 39 | { 40 | return this.proxy.PublishAsync(request, cancellationToken); 41 | } 42 | 43 | public Task PullMessagesAsync(PubSubPullMessagesTopic topic, MessageDeliveryHandler deliveryHandler, CancellationToken cancellationToken = default) 44 | { 45 | return this.proxy.PullMessagesAsync(topic, deliveryHandler, cancellationToken); 46 | } 47 | 48 | #endregion 49 | } 50 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/PubSub/PubSubPublishRequestTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.PluggableComponents.Utilities; 15 | using Dapr.Proto.Components.V1; 16 | using Google.Protobuf; 17 | using Xunit; 18 | 19 | namespace Dapr.PluggableComponents.Components.PubSub; 20 | 21 | public sealed class PubSubPublishRequestTests 22 | { 23 | [Fact] 24 | public void FromPublishRequestTests() 25 | { 26 | // NOTE: Conversion from gRPC request content type is not symmetric with the reverse, 27 | // so one cannot use the ConversionAssert.ContentTypeEqual() method. 28 | ConversionAssert.Equal( 29 | contentType => new PublishRequest { ContentType = contentType }, 30 | (_, request) => PubSubPublishRequest.FromPublishRequest(request), 31 | request => request.ContentType, 32 | new (string, string?)[] 33 | { 34 | ("", ""), 35 | ("application/json", "application/json") 36 | }); 37 | 38 | ConversionAssert.DataEqual( 39 | data => new PublishRequest { Data = ByteString.CopyFrom(data) }, 40 | request => PubSubPublishRequest.FromPublishRequest(request), 41 | request => request.Data.ToArray()); 42 | 43 | ConversionAssert.MetadataEqual( 44 | metadata => 45 | { 46 | var request = new PublishRequest(); 47 | 48 | request.Metadata.Add(metadata); 49 | 50 | return request; 51 | }, 52 | request => PubSubPublishRequest.FromPublishRequest(request), 53 | request => request.Metadata); 54 | 55 | ConversionAssert.StringEqual( 56 | pubSubName => new PublishRequest { PubsubName = pubSubName }, 57 | request => PubSubPublishRequest.FromPublishRequest(request), 58 | request => request.PubSubName); 59 | 60 | ConversionAssert.StringEqual( 61 | topic => new PublishRequest { Topic = topic }, 62 | request => PubSubPublishRequest.FromPublishRequest(request), 63 | request => request.Topic); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/PubSub/PubSubPullMessagesResponseTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Xunit; 15 | 16 | namespace Dapr.PluggableComponents.Components.PubSub; 17 | 18 | public sealed class PubSubPullMessagesResponseTests 19 | { 20 | [Fact] 21 | public void ToPullMessagesResponseTests() 22 | { 23 | ConversionAssert.ContentTypeEqual( 24 | contentType => new PubSubPullMessagesResponse("topic") { ContentType = contentType }, 25 | response => PubSubPullMessagesResponse.ToPullMessagesResponse("id", response), 26 | response => response.ContentType); 27 | 28 | ConversionAssert.DataEqual( 29 | data => new PubSubPullMessagesResponse("topic") { Data = data }, 30 | response => PubSubPullMessagesResponse.ToPullMessagesResponse("id", response), 31 | response => response.Data); 32 | 33 | ConversionAssert.MetadataEqual( 34 | metadata => new PubSubPullMessagesResponse("topic") { Metadata = metadata }, 35 | response => PubSubPullMessagesResponse.ToPullMessagesResponse("id", response), 36 | response => response.Metadata); 37 | 38 | ConversionAssert.StringEqual( 39 | _ => new PubSubPullMessagesResponse("topic"), 40 | (id, response) => PubSubPullMessagesResponse.ToPullMessagesResponse(id, response), 41 | response => response.Id); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/PubSub/PubSubPullMessagesTopicTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.PluggableComponents.Utilities; 15 | using Dapr.Proto.Components.V1; 16 | using Xunit; 17 | 18 | namespace Dapr.PluggableComponents.Components.PubSub; 19 | 20 | public sealed class PubSubPullMessagesTopicTests 21 | { 22 | [Fact] 23 | public void FromTopicTests() 24 | { 25 | ConversionAssert.MetadataEqual( 26 | metadata => 27 | { 28 | var topic = new Topic(); 29 | 30 | topic.Metadata.Add(metadata); 31 | 32 | return topic; 33 | }, 34 | PubSubPullMessagesTopic.FromTopic, 35 | topic => topic.Metadata); 36 | 37 | ConversionAssert.StringEqual( 38 | name => new Topic { Name = name }, 39 | PubSubPullMessagesTopic.FromTopic, 40 | topic => topic.Name); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/StateStore/MockBulkStateStore.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components.StateStore; 15 | 16 | internal interface IMockBulkStateStore : IMockStateStore, IBulkStateStore where T : class 17 | { 18 | } 19 | 20 | internal sealed class MockBulkStateStore : MockStateStore, IBulkStateStore where T : class 21 | { 22 | private readonly IMockBulkStateStore proxy; 23 | 24 | public MockBulkStateStore(IMockBulkStateStore proxy) 25 | : base(proxy) 26 | { 27 | this.proxy = proxy; 28 | } 29 | 30 | #region IBulkStateStore Members 31 | 32 | public Task BulkDeleteAsync(StateStoreDeleteRequest[] requests, CancellationToken cancellationToken = default) 33 | { 34 | return this.proxy.BulkDeleteAsync(requests, cancellationToken); 35 | } 36 | 37 | public Task BulkGetAsync(StateStoreGetRequest[] requests, CancellationToken cancellationToken = default) 38 | { 39 | return this.proxy.BulkGetAsync(requests, cancellationToken); 40 | } 41 | 42 | public Task BulkSetAsync(StateStoreSetRequest[] requests, CancellationToken cancellationToken = default) 43 | { 44 | return this.proxy.BulkSetAsync(requests, cancellationToken); 45 | } 46 | 47 | #endregion 48 | } 49 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/StateStore/MockQueryableStateStore.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components.StateStore; 15 | 16 | internal interface IMockQueryableStateStore : IMockStateStore, IQueryableStateStore where T : class 17 | { 18 | } 19 | 20 | internal sealed class MockQueryableStateStore : MockStateStore, IQueryableStateStore where T : class 21 | { 22 | private readonly IMockQueryableStateStore proxy; 23 | 24 | public MockQueryableStateStore(IMockQueryableStateStore proxy) 25 | : base(proxy) 26 | { 27 | this.proxy = proxy; 28 | } 29 | 30 | #region IQueryableMockStateStore Members 31 | 32 | public Task QueryAsync(StateStoreQueryRequest request, CancellationToken cancellationToken = default) 33 | { 34 | return this.proxy.QueryAsync(request, cancellationToken); 35 | } 36 | 37 | #endregion 38 | } 39 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/StateStore/MockStateStore.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components.StateStore; 15 | 16 | internal interface IMockStateStore : IMockPluggableComponent, IStateStore where T : class 17 | { 18 | } 19 | 20 | internal class MockStateStore : IStateStore where T : class 21 | { 22 | private readonly IMockStateStore proxy; 23 | 24 | public MockStateStore(IMockStateStore proxy) 25 | { 26 | this.proxy = proxy; 27 | 28 | this.proxy.Create(); 29 | } 30 | 31 | #region IStateStore Members 32 | 33 | public Task DeleteAsync(StateStoreDeleteRequest request, CancellationToken cancellationToken = default) 34 | { 35 | return this.proxy.DeleteAsync(request, cancellationToken); 36 | } 37 | 38 | public Task GetAsync(StateStoreGetRequest request, CancellationToken cancellationToken = default) 39 | { 40 | return this.proxy.GetAsync(request, cancellationToken); 41 | } 42 | 43 | public Task InitAsync(MetadataRequest request, CancellationToken cancellationToken = default) 44 | { 45 | return this.proxy.InitAsync(request, cancellationToken); 46 | } 47 | 48 | public Task SetAsync(StateStoreSetRequest request, CancellationToken cancellationToken = default) 49 | { 50 | return this.proxy.SetAsync(request, cancellationToken); 51 | } 52 | 53 | #endregion 54 | } 55 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/StateStore/MockTransactionalStateStore.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components.StateStore; 15 | 16 | internal interface IMockTransactionalStateStore : IMockStateStore, ITransactionalStateStore where T : class 17 | { 18 | } 19 | 20 | internal sealed class MockTransactionalStateStore : MockStateStore, ITransactionalStateStore where T : class 21 | { 22 | private readonly IMockTransactionalStateStore proxy; 23 | 24 | public MockTransactionalStateStore(IMockTransactionalStateStore proxy) 25 | : base(proxy) 26 | { 27 | this.proxy = proxy; 28 | } 29 | 30 | #region ITransactionalStateStore Members 31 | 32 | public Task TransactAsync(StateStoreTransactRequest request, CancellationToken cancellationToken = default) 33 | { 34 | return this.proxy.TransactAsync(request, cancellationToken); 35 | } 36 | 37 | #endregion 38 | } 39 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/StateStore/StateStoreGetRequestTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.Proto.Components.V1; 15 | using Xunit; 16 | 17 | namespace Dapr.PluggableComponents.Components.StateStore; 18 | 19 | public sealed class StateStoreGetRequestTests 20 | { 21 | [Theory] 22 | [InlineData("", "")] 23 | [InlineData("key", "key")] 24 | public void FromGetRequestKeyTests(string key, string expectedKey) 25 | { 26 | var grpcRequest = new GetRequest 27 | { 28 | Key = key 29 | }; 30 | 31 | var request = StateStoreGetRequest.FromGetRequest(grpcRequest); 32 | 33 | Assert.Equal(expectedKey, request.Key); 34 | } 35 | 36 | public static IEnumerable MetadataTests => 37 | new[]{ 38 | new[] 39 | { 40 | new Dictionary() 41 | }, 42 | new[] 43 | { 44 | new Dictionary 45 | { 46 | { "key1", "value1" }, 47 | { "key2", "value2" } 48 | } 49 | } 50 | }; 51 | 52 | [Theory] 53 | [MemberData(nameof(MetadataTests))] 54 | public void FromGetRequestMetadataTests(IDictionary metadata) 55 | { 56 | var grpcRequest = new GetRequest(); 57 | 58 | grpcRequest.Metadata.Add(metadata); 59 | 60 | var request = StateStoreGetRequest.FromGetRequest(grpcRequest); 61 | 62 | Assert.Equal(metadata, request.Metadata); 63 | } 64 | 65 | [Theory] 66 | [InlineData(StateOptions.Types.StateConsistency.ConsistencyEventual, StateStoreConsistency.Eventual)] 67 | [InlineData(StateOptions.Types.StateConsistency.ConsistencyStrong, StateStoreConsistency.Strong)] 68 | [InlineData(StateOptions.Types.StateConsistency.ConsistencyUnspecified, StateStoreConsistency.Unspecified)] 69 | public void FromGetRequestConsistencyTests(StateOptions.Types.StateConsistency grpcConsistency, StateStoreConsistency expectedConsistency) 70 | { 71 | var grpcRequest = new GetRequest 72 | { 73 | Consistency = grpcConsistency 74 | }; 75 | 76 | var request = StateStoreGetRequest.FromGetRequest(grpcRequest); 77 | 78 | Assert.Equal(expectedConsistency, request.Consistency); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/StateStore/StateStoreQueryItemTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Xunit; 15 | 16 | namespace Dapr.PluggableComponents.Components.StateStore; 17 | 18 | public sealed class StateStoreQueryItemTests 19 | { 20 | [Fact] 21 | public void ToQueryItemConversionTests() 22 | { 23 | var converter = StateStoreQueryItem.ToQueryItem; 24 | 25 | ConversionAssert.ContentTypeEqual( 26 | contentType => new StateStoreQueryItem("key") { ContentType = contentType }, 27 | converter, 28 | item => item.ContentType); 29 | 30 | ConversionAssert.DataEqual( 31 | data => new StateStoreQueryItem("key") { Data = data }, 32 | converter, 33 | item => item.Data); 34 | 35 | ConversionAssert.NullableStringEqual( 36 | error => new StateStoreQueryItem("key") { Error = error }, 37 | converter, 38 | item => item.Error); 39 | 40 | ConversionAssert.ETagEqual( 41 | etag => new StateStoreQueryItem("key") { ETag = etag }, 42 | converter, 43 | item => item.Etag); 44 | 45 | ConversionAssert.StringEqual( 46 | key => new StateStoreQueryItem(key), 47 | converter, 48 | item => item.Key); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/StateStore/StateStoreQueryPaginationTests.cs: -------------------------------------------------------------------------------- 1 | using Dapr.Proto.Components.V1; 2 | using Xunit; 3 | 4 | namespace Dapr.PluggableComponents.Components.StateStore; 5 | 6 | public sealed class StateStoreQueryPaginationTests 7 | { 8 | [Fact] 9 | public void FromPaginationConversionTests() 10 | { 11 | var converter = StateStoreQueryPagination.FromPagination; 12 | StateStoreQueryPagination? curriedConverter(T _, Pagination? pagination) => converter(pagination); 13 | 14 | ConversionAssert.Equal( 15 | limit => limit.HasValue ? new Pagination { Limit = limit.Value } : null, 16 | curriedConverter, 17 | pagination => pagination?.Limit, 18 | new (long?, long?)[] 19 | { 20 | (null, null), 21 | (0, 0), 22 | (123, 123) 23 | }); 24 | 25 | ConversionAssert.Equal( 26 | token => token != null ? new Pagination { Token = token } : null, 27 | curriedConverter, 28 | pagination => pagination?.Token, 29 | new[] 30 | { 31 | (null, null), 32 | ("", ""), 33 | ("token", "token") 34 | }); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/StateStore/StateStoreQueryRequestTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.PluggableComponents.Utilities; 15 | using Dapr.Proto.Components.V1; 16 | using Xunit; 17 | 18 | namespace Dapr.PluggableComponents.Components.StateStore; 19 | 20 | public sealed class StateStoreQueryRequestsTests 21 | { 22 | [Fact] 23 | public void FromQueryRequestConversionTests() 24 | { 25 | ConversionAssert.MetadataEqual( 26 | metadata => 27 | { 28 | var request = new QueryRequest(); 29 | 30 | request.Metadata.Add(metadata); 31 | 32 | return request; 33 | }, 34 | StateStoreQueryRequest.FromQueryRequest, 35 | request => request.Metadata); 36 | 37 | var nonEmptyQuery = new Query(); 38 | 39 | ConversionAssert.Equal( 40 | query => new QueryRequest { Query = query }, 41 | (_, request) => StateStoreQueryRequest.FromQueryRequest(request), 42 | request => request.Query, 43 | new[] 44 | { 45 | (null, null), 46 | (new Query(), new StateStoreQuery()) 47 | }, 48 | (expected, actual) => 49 | { 50 | if (expected != null) 51 | { 52 | Assert.NotNull(actual); 53 | } 54 | else 55 | { 56 | Assert.Null(actual); 57 | } 58 | }); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/StateStore/StateStoreQueryResponseTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Xunit; 15 | 16 | namespace Dapr.PluggableComponents.Components.StateStore; 17 | 18 | public sealed class StateStoreQueryResponseTests 19 | { 20 | [Fact] 21 | public void ToQueryResponseConversionTests() 22 | { 23 | IEnumerable empty = new string[] { }; 24 | IEnumerable nonEmpty = new[] { "key1", "key2" }; 25 | 26 | var converter = StateStoreQueryResponse.ToQueryResponse; 27 | 28 | ConversionAssert.Equal( 29 | items => new StateStoreQueryResponse { Items = items.Select(item => new StateStoreQueryItem(item)).ToArray() }, 30 | (_, response) => converter(response), 31 | response => response.Items.Select(item => item.Key), 32 | new[] 33 | { 34 | (empty, empty), 35 | (nonEmpty, nonEmpty) 36 | }); 37 | 38 | ConversionAssert.NullableStringEqual( 39 | token => new StateStoreQueryResponse { Token = token }, 40 | converter, 41 | response => response.Token); 42 | 43 | ConversionAssert.MetadataEqual( 44 | metadata => new StateStoreQueryResponse { Metadata = metadata }, 45 | converter, 46 | response => response.Metadata); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/StateStore/StateStoreQuerySortingTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.Proto.Components.V1; 15 | using Xunit; 16 | 17 | namespace Dapr.PluggableComponents.Components.StateStore; 18 | 19 | public sealed class StateStoreQuerySortingTests 20 | { 21 | [Fact] 22 | public void FromSortingConversionTests() 23 | { 24 | var converter = StateStoreQuerySorting.FromSorting; 25 | StateStoreQuerySorting curriedConverter(T _, Sorting request) => converter(request); 26 | 27 | ConversionAssert.StringEqual( 28 | key => new Sorting { Key = key }, 29 | converter, 30 | sorting => sorting.Key); 31 | 32 | ConversionAssert.Equal( 33 | order => new Sorting { Order = order }, 34 | curriedConverter, 35 | sorting => sorting.Order, 36 | new[] 37 | { 38 | (Sorting.Types.Order.Asc, StateStoreQuerySortingOrder.Ascending), 39 | (Sorting.Types.Order.Desc, StateStoreQuerySortingOrder.Descending) 40 | }); 41 | } 42 | 43 | [Theory] 44 | [InlineData(Sorting.Types.Order.Asc, StateStoreQuerySortingOrder.Ascending)] 45 | [InlineData(Sorting.Types.Order.Desc, StateStoreQuerySortingOrder.Descending)] 46 | public void FromSortingOrderTests(Sorting.Types.Order order, StateStoreQuerySortingOrder expected) 47 | { 48 | var actual = StateStoreQuerySorting.FromSortingOrder(order); 49 | 50 | Assert.Equal(expected, actual); 51 | } 52 | 53 | [Fact] 54 | public void FromSortingOrderTestsUnknown() 55 | { 56 | Assert.Throws(() => StateStoreQuerySorting.FromSortingOrder((Sorting.Types.Order)(-1))); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/StateStore/StateStoreSetRequestTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.PluggableComponents.Utilities; 15 | using Dapr.Proto.Components.V1; 16 | using Xunit; 17 | 18 | namespace Dapr.PluggableComponents.Components.StateStore; 19 | 20 | public sealed class StateStoreSetRequestTests 21 | { 22 | [Fact] 23 | public void FromSetRequestConversionTests() 24 | { 25 | var converter = StateStoreSetRequest.FromSetRequest; 26 | StateStoreSetRequest curriedConverter(T _, SetRequest request) => converter(request); 27 | 28 | // NOTE: Conversion from gRPC request content type is not symmetric with the reverse, 29 | // so one cannot use the ConversionAssert.ContentTypeEqual() method. 30 | ConversionAssert.Equal( 31 | contentType => new SetRequest { ContentType = contentType }, 32 | curriedConverter, 33 | request => request.ContentType, 34 | new (string, string?)[] 35 | { 36 | ("", ""), 37 | ("application/json", "application/json") 38 | }); 39 | 40 | ConversionAssert.Equal( 41 | etag => new SetRequest { Etag = etag }, 42 | curriedConverter, 43 | request => request.ETag, 44 | new[] 45 | { 46 | (null, null), 47 | (new Etag { Value = "" }, ""), 48 | (new Etag { Value = "value" }, "value") 49 | }); 50 | 51 | ConversionAssert.Equal( 52 | options => new SetRequest { Options = options }, 53 | curriedConverter, 54 | request => request.Options, 55 | new[] 56 | { 57 | (null, null), 58 | (new StateOptions(), new StateStoreStateOptions()) 59 | }); 60 | 61 | ConversionAssert.MetadataEqual( 62 | metadata => 63 | { 64 | var request = new SetRequest(); 65 | 66 | request.Metadata.Add(metadata); 67 | 68 | return request; 69 | }, 70 | converter, 71 | request => request.Metadata); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/StateStore/StateStoreStateOptionsTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.Proto.Components.V1; 15 | using Xunit; 16 | 17 | namespace Dapr.PluggableComponents.Components.StateStore; 18 | 19 | public sealed class StateStoreStateOptionsTests 20 | { 21 | [Fact] 22 | public void FromStateOptionsTests() 23 | { 24 | StateOptions? grpcOptions = null; 25 | 26 | var options = StateStoreStateOptions.FromStateOptions(grpcOptions); 27 | 28 | Assert.Null(options); 29 | 30 | grpcOptions = new StateOptions 31 | { 32 | Concurrency = StateOptions.Types.StateConcurrency.ConcurrencyFirstWrite, 33 | Consistency = StateOptions.Types.StateConsistency.ConsistencyEventual 34 | }; 35 | 36 | options = StateStoreStateOptions.FromStateOptions(grpcOptions); 37 | 38 | Assert.NotNull(options); 39 | 40 | Assert.Equal(StateStoreConcurrency.FirstWrite, options.Concurrency); 41 | Assert.Equal(StateStoreConsistency.Eventual, options.Consistency); 42 | } 43 | 44 | [Theory] 45 | [InlineData(StateOptions.Types.StateConcurrency.ConcurrencyFirstWrite, StateStoreConcurrency.FirstWrite)] 46 | [InlineData(StateOptions.Types.StateConcurrency.ConcurrencyLastWrite, StateStoreConcurrency.LastWrite)] 47 | [InlineData(StateOptions.Types.StateConcurrency.ConcurrencyUnspecified, StateStoreConcurrency.Unspecified)] 48 | public void FromStateOptionsConcurrencyTests(StateOptions.Types.StateConcurrency grpcConcurrency, StateStoreConcurrency expectedConcurrency) 49 | { 50 | var grpcOptions = new StateOptions 51 | { 52 | Concurrency = grpcConcurrency 53 | }; 54 | 55 | var options = StateStoreStateOptions.FromStateOptions(grpcOptions); 56 | 57 | Assert.NotNull(options); 58 | Assert.Equal(expectedConcurrency, options.Concurrency); 59 | } 60 | 61 | [Theory] 62 | [InlineData(StateOptions.Types.StateConsistency.ConsistencyEventual, StateStoreConsistency.Eventual)] 63 | [InlineData(StateOptions.Types.StateConsistency.ConsistencyStrong, StateStoreConsistency.Strong)] 64 | [InlineData(StateOptions.Types.StateConsistency.ConsistencyUnspecified, StateStoreConsistency.Unspecified)] 65 | public void FromStateOptionsConsistencyTests(StateOptions.Types.StateConsistency grpcConsistency, StateStoreConsistency expectedConsistency) 66 | { 67 | var grpcOptions = new StateOptions 68 | { 69 | Consistency = grpcConsistency 70 | }; 71 | 72 | var options = StateStoreStateOptions.FromStateOptions(grpcOptions); 73 | 74 | Assert.NotNull(options); 75 | Assert.Equal(expectedConsistency, options.Consistency); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/StateStore/StateStoreTransactOperationTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.Proto.Components.V1; 15 | using Xunit; 16 | 17 | namespace Dapr.PluggableComponents.Components.StateStore; 18 | 19 | public sealed class StateStoreTransactOperationTests 20 | { 21 | [Fact] 22 | public void FromTransactionalStateOperationDelete() 23 | { 24 | string key = "key"; 25 | 26 | var grpcOperation = new TransactionalStateOperation 27 | { 28 | Delete = new DeleteRequest { Key = key } 29 | }; 30 | 31 | var operation = StateStoreTransactOperation.FromTransactionalStateOperation(grpcOperation); 32 | 33 | var request = operation.Visit( 34 | deleteRequest => deleteRequest, 35 | setRequest => null); 36 | 37 | Assert.NotNull(request); 38 | Assert.Equal(key, request.Key); 39 | } 40 | 41 | [Fact] 42 | public void FromTransactionalStateOperationSet() 43 | { 44 | string key = "key"; 45 | 46 | var grpcOperation = new TransactionalStateOperation 47 | { 48 | Set = new SetRequest { Key = key } 49 | }; 50 | 51 | var operation = StateStoreTransactOperation.FromTransactionalStateOperation(grpcOperation); 52 | 53 | var request = operation.Visit( 54 | deleteRequest => null, 55 | setRequest => setRequest); 56 | 57 | Assert.NotNull(request); 58 | Assert.Equal(key, request.Key); 59 | } 60 | 61 | [Fact] 62 | public void FromTransactionalStateOperationUnknown() 63 | { 64 | var grpcOperation = new TransactionalStateOperation(); 65 | 66 | Assert.Throws(() => StateStoreTransactOperation.FromTransactionalStateOperation(grpcOperation)); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Components/StateStore/StateStoreTransactRequestTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.PluggableComponents.Utilities; 15 | using Dapr.Proto.Components.V1; 16 | using Xunit; 17 | 18 | namespace Dapr.PluggableComponents.Components.StateStore; 19 | 20 | public sealed class StateStoreTransactRequestTests 21 | { 22 | [Fact] 23 | public void FromTransactionalStateRequestConversionTests() 24 | { 25 | ConversionAssert.MetadataEqual( 26 | metadata => 27 | { 28 | var request = new TransactionalStateRequest(); 29 | 30 | request.Metadata.Add(metadata); 31 | 32 | return request; 33 | }, 34 | StateStoreTransactRequest.FromTransactionalStateRequest, 35 | request => request.Metadata); 36 | } 37 | 38 | [Fact] 39 | public void FromTransactionalStateRequestOperationsTests() 40 | { 41 | var grpcRequest = new TransactionalStateRequest(); 42 | 43 | string key1 = "key1"; 44 | string key2 = "key2"; 45 | 46 | grpcRequest.Operations.Add(new TransactionalStateOperation { Delete = new DeleteRequest { Key = key1 } }); 47 | grpcRequest.Operations.Add(new TransactionalStateOperation { Set = new SetRequest { Key = key2 } }); 48 | 49 | var request = StateStoreTransactRequest.FromTransactionalStateRequest(grpcRequest); 50 | 51 | Assert.NotNull(request); 52 | Assert.Equal(2, request.Operations.Length); 53 | 54 | var operation1 = request.Operations[0]; 55 | var operation2 = request.Operations[1]; 56 | 57 | Assert.Equal(key1, operation1.Visit(deleteRequest => deleteRequest, setRequest => null)?.Key); 58 | Assert.Equal(key2, operation2.Visit(deleteRequest => null, setRequest => setRequest)?.Key); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Dapr.PluggableComponents.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | all 16 | 17 | 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | all 20 | 21 | 22 | 23 | 24 | 25 | runtime; build; native; contentfiles; analyzers; buildtransitive 26 | all 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/DaprPluggableComponentsApplicationTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Xunit; 15 | 16 | namespace Dapr.PluggableComponents; 17 | 18 | public sealed class DaprPluggableComponentsApplicationTests 19 | { 20 | private const int TimeoutInMs = 10000; 21 | 22 | [Fact(Timeout = TimeoutInMs)] 23 | public async Task RunAsync() 24 | { 25 | var application = DaprPluggableComponentsApplication.Create(); 26 | 27 | var runTask = application.RunAsync(); 28 | 29 | var stopAfterDelay = 30 | async () => 31 | { 32 | await Task.Delay(TimeSpan.FromSeconds(1)); 33 | 34 | await application.StopAsync(); 35 | }; 36 | 37 | await Task.WhenAll(runTask, stopAfterDelay()); 38 | } 39 | 40 | [Fact(Timeout = TimeoutInMs)] 41 | public async Task RunAsyncWithCancellation() 42 | { 43 | var application = DaprPluggableComponentsApplication.Create(); 44 | 45 | using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); 46 | 47 | await application.RunAsync(cts.Token); 48 | } 49 | 50 | [Fact(Timeout = TimeoutInMs)] 51 | public async Task Run() 52 | { 53 | var application = DaprPluggableComponentsApplication.Create(); 54 | 55 | var runTask = Task.Run( 56 | () => 57 | { 58 | application.Run(); 59 | }); 60 | 61 | await Task.Delay(TimeSpan.FromSeconds(1)); 62 | 63 | await application.StopAsync(); 64 | 65 | await runTask; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/SocketFixture.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using System.Net.Sockets; 15 | using Grpc.Net.Client; 16 | 17 | namespace Dapr.PluggableComponents; 18 | 19 | internal sealed class SocketFixture : IDisposable 20 | { 21 | private readonly Lazy grpcChannel; 22 | private readonly Lazy serviceOptions; 23 | 24 | public SocketFixture() 25 | { 26 | this.grpcChannel = new Lazy( 27 | () => GrpcChannel.ForAddress( 28 | "http://localhost", 29 | new GrpcChannelOptions 30 | { 31 | HttpHandler = 32 | new SocketsHttpHandler 33 | { 34 | ConnectCallback = 35 | async (_, cancellationToken) => 36 | { 37 | var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified); 38 | 39 | try 40 | { 41 | await socket.ConnectAsync(new UnixDomainSocketEndPoint(this.SocketPath), cancellationToken); 42 | 43 | return new NetworkStream(socket, true); 44 | } 45 | catch 46 | { 47 | socket.Dispose(); 48 | 49 | throw; 50 | } 51 | } 52 | } 53 | })); 54 | 55 | this.serviceOptions = new Lazy( 56 | () => new DaprPluggableComponentsServiceOptions(Path.GetFileNameWithoutExtension(this.SocketPath)) 57 | { 58 | SocketExtension = Path.GetExtension(this.SocketPath), 59 | SocketFolder = Path.GetDirectoryName(this.SocketPath) 60 | }); 61 | } 62 | 63 | public GrpcChannel GrpcChannel => this.grpcChannel.Value; 64 | 65 | public DaprPluggableComponentsServiceOptions ServiceOptions => this.serviceOptions.Value; 66 | 67 | private string SocketPath { get; } = Path.GetTempFileName(); 68 | 69 | #region IDisposable Members 70 | 71 | public void Dispose() 72 | { 73 | if (this.grpcChannel.IsValueCreated) 74 | { 75 | this.grpcChannel.Value.Dispose(); 76 | } 77 | 78 | if (File.Exists(this.SocketPath)) 79 | { 80 | File.Delete(this.SocketPath); 81 | } 82 | } 83 | 84 | #endregion 85 | } 86 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/TestConstants.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents; 15 | 16 | internal static class TestConstants 17 | { 18 | public static class Metadata 19 | { 20 | public const string ComponentInstanceId = "x-component-instance"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.Tests/Unit.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents; 15 | 16 | /// 17 | /// Represents dummy types used to ensure uniqueness when registering types with DI containers. 18 | /// 19 | /// 20 | /// Registering singleton types in DI containers rely on unique concrete types. If tests need 21 | /// to register multiple, similar types (e.g. multiple state stores), tests would need to 22 | /// implement several nearly identical mock classes, which is tedious. Instead, a single mock 23 | /// class be generic and rely on these unit types to easily generate multiple concrete types. 24 | /// 25 | internal class Unit 26 | { 27 | public class A 28 | { 29 | } 30 | 31 | public class B 32 | { 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31903.59 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.PluggableComponents", "Dapr.PluggableComponents\Dapr.PluggableComponents.csproj", "{564281B0-DAAF-4CA9-B470-F2303DFADC27}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.PluggableComponents.AspNetCore", "Dapr.PluggableComponents.AspNetCore\Dapr.PluggableComponents.AspNetCore.csproj", "{F8E0AAC3-6E11-48B6-9548-BD172322E3DB}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.PluggableComponents.Protos", "Dapr.PluggableComponents.Protos\Dapr.PluggableComponents.Protos.csproj", "{162F5F8C-6A5B-4DED-A51E-52E2EBC9C3A5}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.PluggableComponents.Tests", "Dapr.PluggableComponents.Tests\Dapr.PluggableComponents.Tests.csproj", "{2A0E9A06-C366-4C05-9945-12EA987FDEF5}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {564281B0-DAAF-4CA9-B470-F2303DFADC27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {564281B0-DAAF-4CA9-B470-F2303DFADC27}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {564281B0-DAAF-4CA9-B470-F2303DFADC27}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {564281B0-DAAF-4CA9-B470-F2303DFADC27}.Release|Any CPU.Build.0 = Release|Any CPU 27 | {F8E0AAC3-6E11-48B6-9548-BD172322E3DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {F8E0AAC3-6E11-48B6-9548-BD172322E3DB}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {F8E0AAC3-6E11-48B6-9548-BD172322E3DB}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {F8E0AAC3-6E11-48B6-9548-BD172322E3DB}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {162F5F8C-6A5B-4DED-A51E-52E2EBC9C3A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {162F5F8C-6A5B-4DED-A51E-52E2EBC9C3A5}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {162F5F8C-6A5B-4DED-A51E-52E2EBC9C3A5}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {162F5F8C-6A5B-4DED-A51E-52E2EBC9C3A5}.Release|Any CPU.Build.0 = Release|Any CPU 35 | {2A0E9A06-C366-4C05-9945-12EA987FDEF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 36 | {2A0E9A06-C366-4C05-9945-12EA987FDEF5}.Debug|Any CPU.Build.0 = Debug|Any CPU 37 | {2A0E9A06-C366-4C05-9945-12EA987FDEF5}.Release|Any CPU.ActiveCfg = Release|Any CPU 38 | {2A0E9A06-C366-4C05-9945-12EA987FDEF5}.Release|Any CPU.Build.0 = Release|Any CPU 39 | EndGlobalSection 40 | EndGlobal 41 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Adaptors/IDaprPluggableComponentProvider.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Grpc.Core; 15 | 16 | namespace Dapr.PluggableComponents.Adaptors; 17 | 18 | /// 19 | /// Represents a means of retrieving the Dapr Pluggable Component instance associated with a given gRPC request. 20 | /// 21 | /// The type of Dapr Pluggable Component being retrieved. 22 | /// 23 | /// As the gRPC protocol adaptors are scoped to requests (i.e. a new instance created for each request), while 24 | /// Dapr Pluggable Components may *not* be, the adaptors use a provider-based mechanism to obtain the component 25 | /// associated with a given request. 26 | /// 27 | public interface IDaprPluggableComponentProvider 28 | { 29 | /// 30 | /// Gets the Dapr Pluggable Component instance associated with a given gRPC request. 31 | /// 32 | /// The gRPC request context. 33 | /// The component instance associated with the request. 34 | T GetComponent(ServerCallContext context); 35 | } 36 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Adaptors/QueryableStateStoreAdaptor.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.PluggableComponents.Components.StateStore; 15 | using Dapr.PluggableComponents.Utilities; 16 | using Dapr.Proto.Components.V1; 17 | using Google.Protobuf; 18 | using Grpc.Core; 19 | using Microsoft.Extensions.Logging; 20 | using static Dapr.Proto.Components.V1.QueriableStateStore; 21 | 22 | namespace Dapr.PluggableComponents.Adaptors; 23 | 24 | /// 25 | /// .NET prefers the "queryable" spelling compared to the protos definition. 26 | /// 27 | public class QueryableStateStoreAdaptor : QueriableStateStoreBase 28 | { 29 | private readonly ILogger logger; 30 | private readonly IDaprPluggableComponentProvider componentProvider; 31 | 32 | /// 33 | /// Creates a new instance of the class. 34 | /// 35 | /// A logger used for internal purposes. 36 | /// A means to obtain the Dapr Pluggable Component associated with this adapter instance. 37 | /// If any parameter is null. 38 | public QueryableStateStoreAdaptor(ILogger logger, IDaprPluggableComponentProvider componentProvider) 39 | { 40 | this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); 41 | this.componentProvider = componentProvider ?? throw new ArgumentNullException(nameof(componentProvider)); 42 | } 43 | 44 | /// 45 | public override async Task Query(QueryRequest request, ServerCallContext context) 46 | { 47 | this.logger.LogDebug("Query request."); 48 | 49 | var response = await this.GetStateStore(context).QueryAsync( 50 | StateStoreQueryRequest.FromQueryRequest(request), 51 | context.CancellationToken); 52 | 53 | return StateStoreQueryResponse.ToQueryResponse(response); 54 | } 55 | 56 | private IQueryableStateStore GetStateStore(ServerCallContext context) 57 | { 58 | return this.componentProvider.GetComponent(context); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Adaptors/TransactionalStateStoreAdaptor.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.PluggableComponents.Components.StateStore; 15 | using Dapr.Proto.Components.V1; 16 | using Grpc.Core; 17 | using Microsoft.Extensions.Logging; 18 | using static Dapr.Proto.Components.V1.TransactionalStateStore; 19 | 20 | namespace Dapr.PluggableComponents.Adaptors; 21 | 22 | /// 23 | /// Represents the gRPC protocol adaptor for a state store Dapr Pluggable Component that supports transactions. 24 | /// 25 | public class TransactionalStateStoreAdaptor : TransactionalStateStoreBase 26 | { 27 | private readonly ILogger logger; 28 | private readonly IDaprPluggableComponentProvider componentProvider; 29 | 30 | /// 31 | /// Creates a new instance of the class. 32 | /// 33 | /// A logger used for internal purposes. 34 | /// A means to obtain the Dapr Pluggable Component associated with this adapter instance. 35 | /// If any parameter is null. 36 | public TransactionalStateStoreAdaptor(ILogger logger, IDaprPluggableComponentProvider componentProvider) 37 | { 38 | this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); 39 | this.componentProvider = componentProvider ?? throw new ArgumentNullException(nameof(componentProvider)); 40 | } 41 | 42 | /// 43 | public override async Task Transact(TransactionalStateRequest request, ServerCallContext context) 44 | { 45 | this.logger.LogDebug("Transact request"); 46 | 47 | await this.GetStateStore(context).TransactAsync( 48 | StateStoreTransactRequest.FromTransactionalStateRequest(request), 49 | context.CancellationToken); 50 | 51 | return new TransactionalStateResponse(); 52 | } 53 | 54 | private ITransactionalStateStore GetStateStore(ServerCallContext context) 55 | { 56 | return this.componentProvider.GetComponent(context); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using System.Runtime.CompilerServices; 15 | 16 | [assembly: InternalsVisibleTo("Dapr.PluggableComponents.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001008ba42b1dc1174caa5d9613d60ac27c5b31cf513e7d4e9360241b3b3dc7f1e2e573dcb0c7a53100eba06ea1731c84d8f24a88e9d01fa22e25a9ee4b935389faa010d2625d0b8f6c357cfd0edaa7a25e28694a18525ac0995b39efa830dbcd812cd014724dc476ee908bf96f9331fba8e3949d24a2a28e0183fa642daec2d9b3aa")] 17 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/Bindings/IInputBinding.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components.Bindings; 15 | 16 | /// 17 | /// Represents an input binding Dapr Pluggable Component. 18 | /// 19 | public interface IInputBinding : IPluggableComponent 20 | { 21 | /// 22 | /// Called to establish a stream through which messages can be returned to the (Dapr) client and Dapr acknowledgements returned to the component. 23 | /// 24 | /// The handler used to deliver messages to the (Dapr) client. 25 | /// The token to monitor for cancellation requests. 26 | /// A representing the asynchronous operation. 27 | Task ReadAsync(MessageDeliveryHandler deliveryHandler, CancellationToken cancellationToken = default); 28 | } 29 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/Bindings/IOutputBinding.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components.Bindings; 15 | 16 | /// 17 | /// Represents an output binding Dapr Pluggable Component. 18 | /// 19 | public interface IOutputBinding : IPluggableComponent 20 | { 21 | /// 22 | /// Called to invoke a bound operation. 23 | /// 24 | /// Properties related to the invocation. 25 | /// The token to monitor for cancellation requests. 26 | /// A representing the asynchronous operation, resulting in the invocation response. 27 | Task InvokeAsync(OutputBindingInvokeRequest request, CancellationToken cancellationToken = default); 28 | 29 | /// 30 | /// Called to return the list of bound operations. 31 | /// 32 | /// The token to monitor for cancellation requests. 33 | /// A representing the asynchronous operation, resulting in the list of bound operation names. 34 | Task ListOperationsAsync(CancellationToken cancellationToken = default); 35 | } 36 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/Bindings/InputBindingReadRequest.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.Proto.Components.V1; 15 | 16 | namespace Dapr.PluggableComponents.Components.Bindings; 17 | 18 | /// 19 | /// Respresents an acknowledgement of the processing of a message by the (Dapr) client. 20 | /// 21 | /// Gets the ID of the processed message. 22 | /// 23 | /// This type is considered a "request" because it is sent to the component by the (Dapr) client. 24 | /// 25 | public sealed record InputBindingReadRequest(string MessageId) 26 | { 27 | /// 28 | /// Gets the message response data, if any. 29 | /// 30 | public ReadOnlyMemory ResponseData { get; init; } = ReadOnlyMemory.Empty; 31 | 32 | /// 33 | /// Gets the error message associated with the message. 34 | /// 35 | /// 36 | /// If omitted, the message should be considered processed successfully. 37 | /// 38 | public string? ResponseErrorMessage { get; init; } 39 | 40 | internal static InputBindingReadRequest FromReadRequest(ReadRequest request) 41 | { 42 | return new InputBindingReadRequest(request.MessageId) 43 | { 44 | ResponseData = request.ResponseData.Memory, 45 | ResponseErrorMessage = request.ResponseError?.Message 46 | }; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/Bindings/InputBindingReadResponse.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.PluggableComponents.Utilities; 15 | using Dapr.Proto.Components.V1; 16 | using Google.Protobuf; 17 | 18 | namespace Dapr.PluggableComponents.Components.Bindings; 19 | 20 | /// 21 | /// Represents a message being sent from the component to the (Dapr) client. 22 | /// 23 | /// 24 | /// This type is considered a "response" because it is sent by the component in response from the (Dapr) client calling 25 | /// . 26 | /// 27 | public sealed record InputBindingReadResponse 28 | { 29 | /// 30 | /// Gets or sets the response data. 31 | /// 32 | public byte[] Data { get; init; } = Array.Empty(); 33 | 34 | /// 35 | /// Gets or sets the metadata associated with the response. 36 | /// 37 | public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); 38 | 39 | /// 40 | /// Gets or sets the content type of the message. 41 | /// 42 | public string? ContentType { get; init; } 43 | 44 | internal static ReadResponse ToReadResponse(string messageId, InputBindingReadResponse response) 45 | { 46 | var grpcResponse = new ReadResponse 47 | { 48 | ContentType = response.ContentType ?? String.Empty, 49 | Data = ByteString.CopyFrom(response.Data ?? Array.Empty()), 50 | MessageId = messageId, 51 | }; 52 | 53 | grpcResponse.Metadata.Add(response.Metadata); 54 | 55 | return grpcResponse; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/Bindings/OutputBindingInvokeRequest.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.Proto.Components.V1; 15 | 16 | namespace Dapr.PluggableComponents.Components.Bindings; 17 | 18 | /// 19 | /// Represents properties associated with an output binding invocation. 20 | /// 21 | /// Gets the name of the operation. 22 | public sealed record OutputBindingInvokeRequest(string Operation) 23 | { 24 | /// 25 | /// Gets the data associated with the invocation, if any. 26 | /// 27 | public ReadOnlyMemory Data { get; init; } = ReadOnlyMemory.Empty; 28 | 29 | /// 30 | /// Gets or sets the metadata associated with the request. 31 | /// 32 | public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); 33 | 34 | internal static OutputBindingInvokeRequest FromInvokeRequest(InvokeRequest request) 35 | { 36 | return new OutputBindingInvokeRequest(request.Operation) 37 | { 38 | Data = request.Data.Memory, 39 | Metadata = request.Metadata 40 | }; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/Bindings/OutputBindingInvokeResponse.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.PluggableComponents.Utilities; 15 | using Dapr.Proto.Components.V1; 16 | using Google.Protobuf; 17 | 18 | namespace Dapr.PluggableComponents.Components.Bindings; 19 | 20 | /// 21 | /// Represents properties associated with the response to an output binding invocation. 22 | /// 23 | public sealed record OutputBindingInvokeResponse 24 | { 25 | /// 26 | /// Gets or sets data associated with the response, if any. 27 | /// 28 | public byte[] Data { get; init; } = Array.Empty(); 29 | 30 | /// 31 | /// Gets or sets the metadata associated with the response. 32 | /// 33 | public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); 34 | 35 | /// 36 | /// Gets or sets the content type of the response data. 37 | /// 38 | public string? ContentType { get; init; } 39 | 40 | internal static InvokeResponse ToInvokeResponse(OutputBindingInvokeResponse response) 41 | { 42 | var grpcResponse = new InvokeResponse 43 | { 44 | ContentType = response.ContentType ?? String.Empty, 45 | Data = ByteString.CopyFrom(response.Data ?? Array.Empty()) 46 | }; 47 | 48 | grpcResponse.Metadata.Add(response.Metadata); 49 | 50 | return grpcResponse; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/IPluggableComponent.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components; 15 | 16 | /// 17 | /// Represents the root interface of all Dapr Pluggable Components. 18 | /// 19 | public interface IPluggableComponent 20 | { 21 | /// 22 | /// Initializes the Dapr Pluggable Component. 23 | /// 24 | /// Metadata associated with this component. 25 | /// The token to monitor for cancellation requests. 26 | /// A representing the asynchronous operation. 27 | /// This method will be invoked once per configured Dapr component. 28 | Task InitAsync(MetadataRequest request, CancellationToken cancellationToken = default); 29 | } 30 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/IPluggableComponentFeatures.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components; 15 | 16 | /// 17 | /// Represents a Dapr Pluggable Component that can describe its supported features. 18 | /// 19 | /// 20 | /// This interface is optional. If not implemented, the component will report no specific features. 21 | /// 22 | public interface IPluggableComponentFeatures 23 | { 24 | /// 25 | /// Gets the features supported by this component. 26 | /// 27 | /// The token to monitor for cancellation requests. 28 | /// A representing the asynchronous operation, resulting in the features supported by this component. 29 | Task GetFeaturesAsync(CancellationToken cancellationToken = default); 30 | } 31 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/IPluggableComponentLiveness.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components; 15 | 16 | /// 17 | /// Represents a Dapr Pluggable Component that can respond to liveness checks. 18 | /// 19 | /// 20 | /// This interface is optional. If not implemented, the component is always considered "live". 21 | /// 22 | public interface IPluggableComponentLiveness 23 | { 24 | /// 25 | /// Called to determine the "liveness" of this component. 26 | /// 27 | /// The token to monitor for cancellation requests. 28 | /// A representing the asynchronous operation. A task that results in 29 | /// indicates this component is "live". Implementors should 30 | /// return a task that results in to indicate this component is not 31 | /// healthy. 32 | Task PingAsync(CancellationToken cancellationToken = default); 33 | } 34 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/MessageDeliveryHandler.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components; 15 | 16 | /// 17 | /// Represents the handler used to receive acknowledgement of a processed message. 18 | /// 19 | /// The request associated with processing the message, if any. 20 | /// A representing the asynchronous operation. 21 | public delegate Task MessageAcknowledgementHandler(TRequest request); 22 | 23 | /// 24 | /// Represents the handler used to deliver messages to the (Dapr) client. 25 | /// 26 | /// The response (i.e. message) to deliver to the (Dapr) client. 27 | /// A handler to receive acknowledgement of the processed message. 28 | /// A representing the asynchronous operation. 29 | public delegate Task MessageDeliveryHandler(TResponse response, MessageAcknowledgementHandler? onAcknowledgement = null); 30 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/MetadataRequest.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components; 15 | 16 | /// 17 | /// Represents metadata associated with a Dapr Pluggable Component during initialization. 18 | /// 19 | public sealed record MetadataRequest 20 | { 21 | /// 22 | /// Gets the component configuration metadata properties. 23 | /// 24 | public IReadOnlyDictionary Properties { get; init; } = new Dictionary(); 25 | 26 | internal static MetadataRequest FromMetadataRequest(Dapr.Client.Autogen.Grpc.v1.MetadataRequest? request) 27 | { 28 | var metadataRequest = new MetadataRequest(); 29 | 30 | if (request != null) 31 | { 32 | metadataRequest = metadataRequest with { Properties = request.Properties }; 33 | } 34 | 35 | return metadataRequest; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/PubSub/IPubSub.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components.PubSub; 15 | 16 | /// 17 | /// Represents a pub-sub Dapr Pluggable Component. 18 | /// 19 | public interface IPubSub : IPluggableComponent 20 | { 21 | /// 22 | /// Called to publish a message. 23 | /// 24 | /// Properties related to the message being published. 25 | /// The token to monitor for cancellation requests. 26 | /// A representing the asynchronous operation. 27 | Task PublishAsync(PubSubPublishRequest request, CancellationToken cancellationToken = default); 28 | 29 | /// 30 | /// Called to establish a stream through which messages can be returned to the (Dapr) client and Dapr acknowledgements returned to the component. 31 | /// 32 | /// The topic for which to pull messages. 33 | /// The handler used to deliver messages to the (Dapr) client. 34 | /// The token to monitor for cancellation requests. 35 | /// A representing the asynchronous operation. 36 | Task PullMessagesAsync(PubSubPullMessagesTopic topic, MessageDeliveryHandler deliveryHandler, CancellationToken cancellationToken = default); 37 | } 38 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/PubSub/PubSubPublishRequest.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.Proto.Components.V1; 15 | 16 | namespace Dapr.PluggableComponents.Components.PubSub; 17 | 18 | /// 19 | /// Represents properties associated with a message to be published. 20 | /// 21 | /// Gets the name of the pub-sub component. 22 | /// Gets the topic on which to publish the message. 23 | public sealed record PubSubPublishRequest(string PubSubName, string Topic) 24 | { 25 | /// 26 | /// Gets the message data. 27 | /// 28 | public ReadOnlyMemory Data { get; init; } = ReadOnlyMemory.Empty; 29 | 30 | /// 31 | /// Gets the metadata associated with the request. 32 | /// 33 | public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); 34 | 35 | /// 36 | /// Gets the content type of the message. 37 | /// 38 | public string? ContentType { get; init; } 39 | 40 | internal static PubSubPublishRequest FromPublishRequest(PublishRequest request) 41 | { 42 | return new PubSubPublishRequest(request.PubsubName, request.Topic) 43 | { 44 | ContentType = request.ContentType, 45 | Data = request.Data.Memory, 46 | Metadata = request.Metadata 47 | }; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/PubSub/PubSubPullMessagesResponse.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.PluggableComponents.Utilities; 15 | using Dapr.Proto.Components.V1; 16 | using Google.Protobuf; 17 | 18 | namespace Dapr.PluggableComponents.Components.PubSub; 19 | 20 | /// 21 | /// Represents a message being "pulled" from the source and delivered to the (Dapr) client. 22 | /// 23 | /// Gets the name of the topic on which the message was published. 24 | /// 25 | /// This type is considered a "response" because it is sent by the component in response to the (Dapr) client calling 26 | /// . 27 | /// 28 | public sealed record PubSubPullMessagesResponse(string TopicName) 29 | { 30 | /// 31 | /// Gets the message data. 32 | /// 33 | public byte[] Data { get; init; } = Array.Empty(); 34 | 35 | /// 36 | /// Gets the metadata associated with the response. 37 | /// 38 | public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); 39 | 40 | /// 41 | /// Gets the content type of the message. 42 | /// 43 | public string? ContentType { get; init; } 44 | 45 | internal static PullMessagesResponse ToPullMessagesResponse(string messageId, PubSubPullMessagesResponse message) 46 | { 47 | var grpcResponse = new PullMessagesResponse 48 | { 49 | ContentType = message.ContentType ?? String.Empty, 50 | Data = message.Data != null ? ByteString.CopyFrom(message.Data) : ByteString.Empty, 51 | Id = messageId, 52 | TopicName = message.TopicName 53 | }; 54 | 55 | grpcResponse.Metadata.Add(message.Metadata); 56 | 57 | return grpcResponse; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/PubSub/PubSubPullMessagesTopic.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.Proto.Components.V1; 15 | 16 | namespace Dapr.PluggableComponents.Components.PubSub; 17 | 18 | /// 19 | /// Represents the topic associated with a message stream. 20 | /// 21 | /// Gets the name of the topic. 22 | public sealed record PubSubPullMessagesTopic(string Name) 23 | { 24 | /// 25 | /// Gets the metadata associated with the topic. 26 | /// 27 | public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); 28 | 29 | internal static PubSubPullMessagesTopic FromTopic(Topic topic) 30 | { 31 | return new PubSubPullMessagesTopic(topic.Name) 32 | { 33 | Metadata = topic.Metadata 34 | }; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/BulkDeleteRowMismatchException.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using System.Globalization; 15 | using Grpc.Core; 16 | 17 | namespace Dapr.PluggableComponents.Components.StateStore; 18 | 19 | /// 20 | /// An exception that represents an occurrence of a bulk deletion not effecting the expected number of rows. 21 | /// 22 | /// 23 | /// This exception should be thrown only from bulk delete operations. 24 | /// 25 | public sealed class BulkDeleteRowMismatchException : RpcException 26 | { 27 | private const StatusCode BaseStatusCode = StatusCode.Internal; 28 | 29 | /// 30 | /// Initializes a new instance of the class. 31 | /// 32 | /// The number of rows expected to be affected. 33 | /// The number of rows actually affected. 34 | public BulkDeleteRowMismatchException(int expectedRows, int affectedRows) 35 | : this(String.Format(CultureInfo.CurrentCulture, Resources.BulkDeleteRowMismatchExceptionMessage, affectedRows, expectedRows), expectedRows, affectedRows) 36 | { 37 | } 38 | 39 | 40 | /// 41 | /// Initializes a new instance of the class with a specific error message. 42 | /// 43 | /// The error message that explains the reason for the exception. 44 | /// The number of rows expected to be affected. 45 | /// The number of rows actually affected. 46 | public BulkDeleteRowMismatchException(string message, int expectedRows, int affectedRows) 47 | : base(new Status(BaseStatusCode, message), StateStoreErrors.GetBulkDeleteRowMismatchErrorMetadata(BaseStatusCode, expectedRows, affectedRows)) 48 | { 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/ETagErrors.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Google.Protobuf; 15 | using Google.Rpc; 16 | using Grpc.Core; 17 | 18 | namespace Dapr.PluggableComponents.Components.StateStore; 19 | 20 | internal static class StateStoreErrors 21 | { 22 | public static Metadata GetETagErrorMetadata(StatusCode statusCode, string message) 23 | { 24 | return GetMetadata(statusCode, GetETagFieldViolation(message)); 25 | } 26 | 27 | public static Metadata GetBulkDeleteRowMismatchErrorMetadata(StatusCode statusCode, int expectedRows, int affectedRows) 28 | { 29 | var errorInfo = new Google.Rpc.ErrorInfo(); 30 | 31 | errorInfo.Metadata.Add("expected", expectedRows.ToString()); 32 | errorInfo.Metadata.Add("affected", affectedRows.ToString()); 33 | 34 | return GetMetadata(statusCode, errorInfo); 35 | } 36 | 37 | private static BadRequest GetETagFieldViolation(string message) 38 | { 39 | var badRequest = new BadRequest(); 40 | 41 | badRequest.FieldViolations.Add( 42 | new Google.Rpc.BadRequest.Types.FieldViolation 43 | { 44 | Field = "etag", 45 | Description = message 46 | }); 47 | 48 | return badRequest; 49 | } 50 | 51 | private static Metadata GetMetadata(StatusCode baseStatusCode, IMessage message) 52 | { 53 | var status = new Google.Rpc.Status 54 | { 55 | Code = (int)baseStatusCode 56 | }; 57 | 58 | status.Details.Add(Google.Protobuf.WellKnownTypes.Any.Pack(message)); 59 | 60 | var metadata = new Metadata(); 61 | 62 | metadata.Add("grpc-status-details-bin", status.ToByteArray()); 63 | 64 | return metadata; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/ETagInvalidException.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Grpc.Core; 15 | 16 | namespace Dapr.PluggableComponents.Components.StateStore; 17 | 18 | /// 19 | /// An exception that represents an invalid ETag. 20 | /// 21 | /// 22 | /// This exception should be thrown for ETag mismatches in the set, bulk set, delete, and bulk delete operations. 23 | /// 24 | public sealed class ETagInvalidException : RpcException 25 | { 26 | private static readonly StatusCode BaseStatusCode = StatusCode.InvalidArgument; 27 | 28 | /// 29 | /// Initializes a new instance of the class. 30 | /// 31 | public ETagInvalidException() 32 | : this(Resources.ETagInvalidExceptionMessage) 33 | { 34 | } 35 | 36 | /// 37 | /// Initializes a new instance of the class with a specific error message. 38 | /// 39 | /// The error message that explains the reason for the exception. 40 | public ETagInvalidException(string message) 41 | : base(new Status(BaseStatusCode, message), StateStoreErrors.GetETagErrorMetadata(BaseStatusCode, message)) 42 | { 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/ETagMismatchException.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Grpc.Core; 15 | 16 | namespace Dapr.PluggableComponents.Components.StateStore; 17 | 18 | /// 19 | /// An exception that represents a possible ETag mismatch. 20 | /// 21 | /// 22 | /// This exception should be thrown for ETag mismatches in the set, bulk set, delete, and bulk delete operations. 23 | /// 24 | public sealed class ETagMismatchException : RpcException 25 | { 26 | private static readonly StatusCode BaseStatusCode = StatusCode.FailedPrecondition; 27 | 28 | /// 29 | /// Initializes a new instance of the class. 30 | /// 31 | public ETagMismatchException() 32 | : this(Resources.ETagMismatchExceptionMessage) 33 | { 34 | } 35 | 36 | /// 37 | /// Initializes a new instance of the class with a specific error message. 38 | /// 39 | /// The error message that explains the reason for the exception. 40 | public ETagMismatchException(string message) 41 | : base(new Status(BaseStatusCode, message), StateStoreErrors.GetETagErrorMetadata(BaseStatusCode, message)) 42 | { 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/IBulkStateStore.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components.StateStore; 15 | 16 | /// 17 | /// Represents a state store Dapr Pluggable Component that supports bulk operations. 18 | /// 19 | /// 20 | /// This interface is optional. If not implemented, bulk operations will be performed via repeated calls to individual methods. 21 | /// 22 | public interface IBulkStateStore 23 | { 24 | /// 25 | /// Called to delete state. 26 | /// 27 | /// Properties related to the state to be deleted. 28 | /// The token to monitor for cancellation requests. 29 | /// A representing the asynchronous operation. 30 | Task BulkDeleteAsync(StateStoreDeleteRequest[] requests, CancellationToken cancellationToken = default); 31 | 32 | /// 33 | /// Called to get state. 34 | /// 35 | /// Properties related to the state to be retrieved. 36 | /// The token to monitor for cancellation requests. 37 | /// A representing the asynchronous operation, resulting in the values returned by the operation. 38 | Task BulkGetAsync(StateStoreGetRequest[] requests, CancellationToken cancellationToken = default); 39 | 40 | /// 41 | /// Called to set or change state. 42 | /// 43 | /// Properties related to the state to be set. 44 | /// The token to monitor for cancellation requests. 45 | /// A representing the asynchronous operation. 46 | Task BulkSetAsync(StateStoreSetRequest[] requests, CancellationToken cancellationToken = default); 47 | } 48 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/IQueryableStateStore.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components.StateStore; 15 | 16 | /// 17 | /// Represents a state store Dapr Pluggable Component that supports query operations. 18 | /// 19 | /// 20 | /// This interface is optional. 21 | /// 22 | public interface IQueryableStateStore 23 | { 24 | /// 25 | /// Called to perform a query. 26 | /// 27 | /// Properties related to the query to be performed. 28 | /// The token to monitor for cancellation requests. 29 | /// A representing the asynchronous operation, resulting in the items returned by the query. 30 | Task QueryAsync(StateStoreQueryRequest request, CancellationToken cancellationToken = default); 31 | } 32 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/IStateStore.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components.StateStore; 15 | 16 | /// 17 | /// Represents a state store Dapr Pluggable Component. 18 | /// 19 | public interface IStateStore : IPluggableComponent 20 | { 21 | /// 22 | /// Called to delete state. 23 | /// 24 | /// Properties related to the state to be deleted. 25 | /// The token to monitor for cancellation requests. 26 | /// A representing the asynchronous operation. 27 | Task DeleteAsync(StateStoreDeleteRequest request, CancellationToken cancellationToken = default); 28 | 29 | /// 30 | /// Called to get state. 31 | /// 32 | /// Properties related to the state to be retrieved. 33 | /// The token to monitor for cancellation requests. 34 | /// A representing the asynchronous operation, resulting in the retrieved state, if any. 35 | Task GetAsync(StateStoreGetRequest request, CancellationToken cancellationToken = default); 36 | 37 | /// 38 | /// Called to set or change state. 39 | /// 40 | /// Properties related to the state to be set. 41 | /// The token to monitor for cancellation requests. 42 | /// A representing the asynchronous operation. 43 | Task SetAsync(StateStoreSetRequest request, CancellationToken cancellationToken = default); 44 | } 45 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/ITransactionalStateStore.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents.Components.StateStore; 15 | 16 | /// 17 | /// Represents a state store Dapr Pluggable Component that supports transactional operations. 18 | /// 19 | /// 20 | /// This interface is optional. 21 | /// 22 | public interface ITransactionalStateStore 23 | { 24 | /// 25 | /// Called to perform a set of operations within a transaction. 26 | /// 27 | /// Properties related to the transaction, such as the operations to be performed. 28 | /// The token to monitor for cancellation requests. 29 | /// A representing the asynchronous operation. 30 | Task TransactAsync(StateStoreTransactRequest request, CancellationToken cancellationToken = default); 31 | } 32 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/StateStoreBulkStateItem.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.PluggableComponents.Utilities; 15 | using Dapr.Proto.Components.V1; 16 | using Google.Protobuf; 17 | 18 | namespace Dapr.PluggableComponents.Components.StateStore; 19 | 20 | /// 21 | /// Represents properties associated with a response to retrieving bulk state from a state store. 22 | /// 23 | /// The key associated with the retrieved value. 24 | public sealed record StateStoreBulkStateItem(string Key) 25 | { 26 | /// 27 | /// Gets the key's content type. 28 | /// 29 | public string? ContentType { get; init; } 30 | 31 | /// 32 | /// Gets the key's value. 33 | /// 34 | public byte[] Data { get; init; } = Array.Empty(); 35 | 36 | /// 37 | /// Gets the error message, if retrieval failed. 38 | /// 39 | public string? Error { get; init; } 40 | 41 | /// 42 | /// Gets the ETag used as an If-Match header, to allow certain levels of consistency. 43 | /// 44 | public string? ETag { get; init; } 45 | 46 | /// 47 | /// Gets the metadata associated with the request. 48 | /// 49 | public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); 50 | 51 | internal static BulkStateItem ToBulkStateItem(StateStoreBulkStateItem item) 52 | { 53 | var bulkStateItem = new BulkStateItem 54 | { 55 | ContentType = item.ContentType ?? String.Empty, 56 | Data = ByteString.CopyFrom(item.Data), 57 | Error = item.Error ?? String.Empty, 58 | Etag = item.ETag != null ? new Etag { Value = item.ETag } : null, 59 | Key = item.Key 60 | }; 61 | 62 | bulkStateItem.Metadata.Add(item.Metadata); 63 | 64 | return bulkStateItem; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/StateStoreDeleteRequest.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.Proto.Components.V1; 15 | 16 | namespace Dapr.PluggableComponents.Components.StateStore; 17 | 18 | /// 19 | /// Represents properties associated with a request to delete state from a state store. 20 | /// 21 | /// The key that should be deleted. 22 | public sealed record StateStoreDeleteRequest(string Key) 23 | { 24 | /// 25 | /// Gets the ETag used as an If-Match header, to allow certain levels of consistency. 26 | /// 27 | public string? ETag { get; init; } 28 | 29 | /// 30 | /// Gets the metadata associated with the request. 31 | /// 32 | public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); 33 | 34 | /// 35 | /// Gets options related to the deletion. 36 | /// 37 | public StateStoreStateOptions? Options { get; init; } 38 | 39 | internal static StateStoreDeleteRequest FromDeleteRequest(DeleteRequest request) 40 | { 41 | return new StateStoreDeleteRequest(request.Key) 42 | { 43 | ETag = request.Etag?.Value, 44 | Metadata = request.Metadata, 45 | Options = StateStoreStateOptions.FromStateOptions(request.Options) 46 | }; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/StateStoreGetRequest.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.Proto.Components.V1; 15 | 16 | namespace Dapr.PluggableComponents.Components.StateStore; 17 | 18 | /// 19 | /// Represents properties associated with a request to retrieve state from a state store. 20 | /// 21 | /// The key that should be retrieved. 22 | public sealed record StateStoreGetRequest(string Key) 23 | { 24 | /// 25 | /// Gets the consistency level for the request. 26 | /// 27 | /// 28 | /// By default, the consistency level is . 29 | /// 30 | public StateStoreConsistency Consistency { get; init; } = StateStoreConsistency.Unspecified; 31 | 32 | /// 33 | /// Gets the metadata associated with the request. 34 | /// 35 | public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); 36 | 37 | internal static StateStoreGetRequest FromGetRequest(GetRequest request) 38 | { 39 | return new StateStoreGetRequest(request.Key) 40 | { 41 | Consistency = (StateStoreConsistency)request.Consistency, 42 | Metadata = request.Metadata 43 | }; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/StateStoreGetResponse.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.PluggableComponents.Utilities; 15 | using Dapr.Proto.Components.V1; 16 | using Google.Protobuf; 17 | 18 | namespace Dapr.PluggableComponents.Components.StateStore; 19 | 20 | /// 21 | /// Represents properties associated with a response to retrieving state from a state store. 22 | /// 23 | public sealed record StateStoreGetResponse 24 | { 25 | /// 26 | /// Gets or sets the key's content type. 27 | /// 28 | /// 29 | /// If omitted, defaults to null. 30 | /// 31 | public string? ContentType { get; init; } 32 | 33 | /// 34 | /// Gets or sets the key's value. 35 | /// 36 | /// 37 | /// If omitted, defaults to an empty array. 38 | /// 39 | public byte[] Data { get; init; } = Array.Empty(); 40 | 41 | /// 42 | /// Gets or sets the ETag used as an If-Match header, to allow certain levels of consistency. 43 | /// 44 | /// 45 | /// If omitted, defaults to null. 46 | /// 47 | public string? ETag { get; init; } 48 | 49 | /// 50 | /// Gets or sets the metadata associated with the request. 51 | /// 52 | /// 53 | /// If omitted, defaults to an empty dictionary. 54 | /// 55 | public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); 56 | 57 | internal static GetResponse ToGetResponse(StateStoreGetResponse? response) 58 | { 59 | var grpcResponse = new GetResponse(); 60 | 61 | // NOTE: in case of not found, you should not return any error. 62 | 63 | if (response != null) 64 | { 65 | grpcResponse.ContentType = response.ContentType ?? String.Empty; 66 | grpcResponse.Data = ByteString.CopyFrom(response.Data); 67 | grpcResponse.Etag = response.ETag != null ? new Etag { Value = response.ETag } : null; 68 | 69 | grpcResponse.Metadata.Add(response.Metadata); 70 | } 71 | 72 | return grpcResponse; 73 | } 74 | 75 | internal static BulkStateItem ToBulkStateItem(string key, StateStoreGetResponse? response) 76 | { 77 | var stateItem = new BulkStateItem 78 | { 79 | Key = key 80 | }; 81 | 82 | if (response != null) 83 | { 84 | stateItem.ContentType = response.ContentType ?? String.Empty; 85 | stateItem.Data = ByteString.CopyFrom(response.Data); 86 | stateItem.Etag = response.ETag != null ? new Etag { Value = response.ETag } : null; 87 | 88 | stateItem.Metadata.Add(response.Metadata); 89 | } 90 | else 91 | { 92 | stateItem.Error = "Unable to fetch the item."; 93 | } 94 | 95 | return stateItem; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/StateStoreQuery.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.Proto.Components.V1; 15 | using Google.Protobuf.WellKnownTypes; 16 | 17 | namespace Dapr.PluggableComponents.Components.StateStore; 18 | 19 | /// 20 | /// Represents a query to be performed on a state store. 21 | /// 22 | public sealed record StateStoreQuery 23 | { 24 | /// 25 | /// Gets properties related to how contents of the state store should be filtered and returned. 26 | /// 27 | public IReadOnlyDictionary Filter { get; init; } = new Dictionary(); 28 | 29 | /// 30 | /// Gets properties related to how results of the query should be paginated, if any. 31 | /// 32 | public StateStoreQueryPagination? Pagination { get; init; } 33 | 34 | /// 35 | /// Gets the keys by which results of the query should be sorted, if any. 36 | /// 37 | public StateStoreQuerySorting[] Sorting { get; init; } = Array.Empty(); 38 | 39 | internal static StateStoreQuery? FromQuery(Query? query) 40 | => query != null 41 | ? new StateStoreQuery 42 | { 43 | Filter = query.Filter, 44 | Pagination = StateStoreQueryPagination.FromPagination(query.Pagination), 45 | Sorting = query.Sort.Select(StateStoreQuerySorting.FromSorting).ToArray() 46 | } 47 | : null; 48 | } 49 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/StateStoreQueryItem.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.Proto.Components.V1; 15 | using Google.Protobuf; 16 | 17 | namespace Dapr.PluggableComponents.Components.StateStore; 18 | 19 | /// 20 | /// Represents an individual item returned by a query of a state store. 21 | /// 22 | /// The state store key associated with the item. 23 | public sealed record StateStoreQueryItem(string Key) 24 | { 25 | /// 26 | /// Gets or sets the key's content type. 27 | /// 28 | /// 29 | /// If omitted, defaults to null. 30 | /// 31 | public string? ContentType { get; init; } 32 | 33 | /// 34 | /// Gets or sets the item's value. 35 | /// 36 | /// 37 | /// If omitted, defaults to an empty array. 38 | /// 39 | public byte[] Data { get; init; } = Array.Empty(); 40 | 41 | /// 42 | /// Gets or sets an error message associated with the query. 43 | /// 44 | /// 45 | /// If omitted, defaults to null. 46 | /// 47 | public string? Error { get; init; } 48 | 49 | /// 50 | /// Gets or sets the ETag used as an If-Match header, to allow certain levels of consistency. 51 | /// 52 | /// 53 | /// If omitted, defaults to null. 54 | /// 55 | public string? ETag { get; init; } 56 | 57 | internal static QueryItem ToQueryItem(StateStoreQueryItem item) 58 | => new QueryItem 59 | { 60 | ContentType = item.ContentType ?? String.Empty, 61 | Data = ByteString.CopyFrom(item.Data ?? Array.Empty()), 62 | Error = item.Error ?? String.Empty, 63 | Etag = item.ETag != null ? new Etag { Value = item.ETag } : null, 64 | Key = item.Key 65 | }; 66 | } 67 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/StateStoreQueryPagination.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.Proto.Components.V1; 15 | 16 | namespace Dapr.PluggableComponents.Components.StateStore; 17 | 18 | /// 19 | /// Represents properties related to how query results should be paginated. 20 | /// 21 | public sealed record StateStoreQueryPagination 22 | { 23 | /// 24 | /// Gets the maximum number of items that should be returned. 25 | /// 26 | public long Limit { get; init; } 27 | 28 | /// 29 | /// Gets the pagination token returned by the previous query, if any. 30 | /// 31 | /// 32 | /// If set, the results of the current query should be a continuation of the previous query. 33 | /// 34 | public string? Token { get; init; } 35 | 36 | internal static StateStoreQueryPagination? FromPagination(Pagination? pagination) 37 | => pagination != null 38 | ? new StateStoreQueryPagination 39 | { 40 | Limit = pagination.Limit, 41 | Token = pagination.Token 42 | } 43 | : null; 44 | } 45 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/StateStoreQueryRequest.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.Proto.Components.V1; 15 | 16 | namespace Dapr.PluggableComponents.Components.StateStore; 17 | 18 | /// 19 | /// Represents properties associated with a request to perform a query of the state store. 20 | /// 21 | public sealed record StateStoreQueryRequest 22 | { 23 | /// 24 | /// Gets the specifics of the query to be performed, if any. 25 | /// 26 | public StateStoreQuery? Query { get; init; } 27 | 28 | /// 29 | /// Gets the metadata associated with the request. 30 | /// 31 | public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); 32 | 33 | internal static StateStoreQueryRequest FromQueryRequest(QueryRequest request) 34 | => new StateStoreQueryRequest 35 | { 36 | Query = StateStoreQuery.FromQuery(request.Query), 37 | Metadata = request.Metadata 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/StateStoreQueryResponse.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.PluggableComponents.Utilities; 15 | using Dapr.Proto.Components.V1; 16 | 17 | namespace Dapr.PluggableComponents.Components.StateStore; 18 | 19 | /// 20 | /// Represents properties associated with a response to a query operation on a state store. 21 | /// 22 | public sealed record StateStoreQueryResponse 23 | { 24 | /// 25 | /// Gets or sets the items returned by the query. 26 | /// 27 | public StateStoreQueryItem[] Items { get; init; } = Array.Empty(); 28 | 29 | /// 30 | /// Gets or sets the metadata associated with the request. 31 | /// 32 | /// 33 | /// If omitted, defaults to an empty dictionary. 34 | /// 35 | public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); 36 | 37 | /// 38 | /// Gets or sets the pagination token used by subsequent requests to get the next set of items. 39 | /// 40 | public string? Token { get; init; } 41 | 42 | internal static QueryResponse ToQueryResponse(StateStoreQueryResponse response) 43 | { 44 | var grpcResponse = new QueryResponse 45 | { 46 | Token = response.Token ?? String.Empty 47 | }; 48 | 49 | grpcResponse.Items.AddRange(response.Items.Select(StateStoreQueryItem.ToQueryItem)); 50 | grpcResponse.Metadata.Add(response.Metadata); 51 | 52 | return grpcResponse; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/StateStoreQuerySorting.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using System.Globalization; 15 | using Dapr.Proto.Components.V1; 16 | 17 | namespace Dapr.PluggableComponents.Components.StateStore; 18 | 19 | /// 20 | /// Represents the order in which query results can be sorted. 21 | /// 22 | public enum StateStoreQuerySortingOrder 23 | { 24 | /// 25 | /// The results are to be sorted in ascending order. 26 | /// 27 | Ascending, 28 | 29 | /// 30 | /// The results are to be sorted in descending order. 31 | /// 32 | Descending 33 | } 34 | 35 | /// 36 | /// Represents one ordering of query results. 37 | /// 38 | /// Gets the state store key on which ordering is performed. 39 | public sealed record StateStoreQuerySorting(string Key) 40 | { 41 | /// 42 | /// Gets the direction in which query results should be sorted, based on the specified key. 43 | /// 44 | /// 45 | /// Defaults to . 46 | /// 47 | public StateStoreQuerySortingOrder Order { get; init; } = StateStoreQuerySortingOrder.Ascending; 48 | 49 | internal static StateStoreQuerySorting FromSorting(Sorting sorting) 50 | => new(sorting.Key) 51 | { 52 | Order = FromSortingOrder(sorting.Order) 53 | }; 54 | 55 | internal static StateStoreQuerySortingOrder FromSortingOrder(Sorting.Types.Order order) 56 | => order switch 57 | { 58 | Sorting.Types.Order.Asc => StateStoreQuerySortingOrder.Ascending, 59 | Sorting.Types.Order.Desc => StateStoreQuerySortingOrder.Descending, 60 | _ => throw new ArgumentOutOfRangeException(nameof(order), String.Format(CultureInfo.CurrentCulture, Resources.StateStoreQuerySortingUnrecognizedOrderMessage, order)) 61 | }; 62 | } 63 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/StateStoreSetRequest.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.Proto.Components.V1; 15 | 16 | namespace Dapr.PluggableComponents.Components.StateStore; 17 | 18 | /// 19 | /// Represents properties associated with a request to set or change state in a state store. 20 | /// 21 | /// The key that should be set. 22 | /// The value to which the key should be set. 23 | public sealed record StateStoreSetRequest(string Key, ReadOnlyMemory Value) 24 | { 25 | /// 26 | /// Gets the key's content type. 27 | /// 28 | public string? ContentType { get; init; } 29 | 30 | /// 31 | /// Gets the ETag used as an If-Match header, to allow certain levels of consistency. 32 | /// 33 | public string? ETag { get; init; } 34 | 35 | /// 36 | /// Gets the metadata associated with the request. 37 | /// 38 | public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); 39 | 40 | /// 41 | /// Gets options related to the change. 42 | /// 43 | public StateStoreStateOptions? Options { get; init; } 44 | 45 | internal static StateStoreSetRequest FromSetRequest(SetRequest request) 46 | { 47 | return new StateStoreSetRequest(request.Key, request.Value.Memory) 48 | { 49 | ContentType = request.ContentType, 50 | ETag = request.Etag?.Value, 51 | Metadata = request.Metadata, 52 | Options = StateStoreStateOptions.FromStateOptions(request.Options) 53 | }; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Components/StateStore/StateStoreTransactRequest.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Dapr.PluggableComponents.Utilities; 15 | using Dapr.Proto.Components.V1; 16 | 17 | namespace Dapr.PluggableComponents.Components.StateStore; 18 | 19 | /// 20 | /// Represents properties associated with a request to perform operations within a transaction. 21 | /// 22 | public sealed record StateStoreTransactRequest 23 | { 24 | /// 25 | /// Gets the operations to be performed as part of the transaction. 26 | /// 27 | public StateStoreTransactOperation[] Operations { get; init; } = Array.Empty(); 28 | 29 | /// 30 | /// Gets the metadata associated with the request. 31 | /// 32 | public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); 33 | 34 | internal static StateStoreTransactRequest FromTransactionalStateRequest(TransactionalStateRequest request) 35 | { 36 | return new StateStoreTransactRequest 37 | { 38 | Metadata = request.Metadata, 39 | Operations = request.Operations.Select(StateStoreTransactOperation.FromTransactionalStateOperation).ToArray() 40 | }; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Constants.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | namespace Dapr.PluggableComponents; 15 | 16 | /// 17 | /// Represents constant values related to Dapr Pluggable Components. 18 | /// 19 | public static class Constants 20 | { 21 | /// 22 | /// Represents default values for Dapr Pluggable Components. 23 | /// 24 | public static class Defaults 25 | { 26 | /// 27 | /// The default extension for socket files created by Dapr Pluggable Components. 28 | /// 29 | public const string DaprComponentsSocketsExtension = ".sock"; 30 | 31 | /// 32 | /// The default temp sub-directory in which Dapr Pluggable Components create their socket files. 33 | /// 34 | public const string DaprComponentsSocketsFolder = "dapr-components-sockets"; 35 | } 36 | 37 | /// 38 | /// Represents names of environment variables related to Dapr Pluggable Components. 39 | /// 40 | public static class EnvironmentVariables 41 | { 42 | /// 43 | /// The environment variable name that defines the exension for socket files created by Dapr Pluggable Components. 44 | /// 45 | /// 46 | /// If not specified, the default value will be used. 47 | /// 48 | public const string DaprComponentsSocketsExtension = "DAPR_COMPONENTS_SOCKETS_EXTENSION"; 49 | 50 | /// 51 | /// The environment variable name that defines the folder in which Dapr Pluggable Components create their socket files. 52 | /// 53 | /// 54 | /// If not specified, the default value will be used. 55 | /// 56 | public const string DaprComponentsSocketsFolder = "DAPR_COMPONENTS_SOCKETS_FOLDER"; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Dapr.PluggableComponents.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | This package contains the reference assemblies for developing pluggable components for Dapr. 9 | $(PackageTags); 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | True 19 | True 20 | Resources.resx 21 | 22 | 23 | 24 | 25 | 26 | ResXFileCodeGenerator 27 | Resources.Designer.cs 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/Dapr.PluggableComponents/Utilities/MapFieldExtensions.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------ 2 | // Copyright 2023 The Dapr Authors 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | // ------------------------------------------------------------------------ 13 | 14 | using Google.Protobuf.Collections; 15 | 16 | namespace Dapr.PluggableComponents.Utilities; 17 | 18 | internal static class MapFieldExtensions 19 | { 20 | public static void Add(this MapField map, IEnumerable>? entries) 21 | { 22 | if (entries != null) 23 | { 24 | foreach (var entry in entries) 25 | { 26 | map.Add(entry.Key, entry.Value); 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0;net8.0 4 | enable 5 | enable 6 | true 7 | 8 | 9 | 10 | 11 | true 12 | $(MSBuildThisFileDirectory)key.snk 13 | 14 | 15 | 16 | Dapr 17 | Copyright 2023 The Dapr Authors 18 | dapr.io 19 | 20 | 21 | 22 | $(MSBuildThisFileDirectory)..\ 23 | 24 | 25 | 26 | 27 | dapr.io 28 | true 29 | Apache-2.0 30 | https://dapr.io 31 | images\logo-transparent.png 32 | Dapr;PluggableComponents 33 | https://github.com/dapr-sandbox/components-dotnet-sdk 34 | git 35 | $(RepoRoot)bin\$(Configuration)\nugets 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | true 46 | snupkg 47 | 48 | 49 | 50 | 51 | 52 | all 53 | runtime; build; native; contentfiles; analyzers; buildtransitive 54 | 55 | 56 | 57 | 58 | 59 | v 60 | rc.0 61 | 62 | 63 | 64 | 65 | 66 | true 67 | true 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | true 76 | 77 | -------------------------------------------------------------------------------- /src/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dapr-sandbox/components-dotnet-sdk/ddba8197c78eba41ab4fb1be119867b0d334a0a1/src/key.snk --------------------------------------------------------------------------------