Compare commits

...

81 Commits

Author SHA1 Message Date
Marc Duiker 407447816c
Update markdown files to be compatible with latest Hugo (#287)
Signed-off-by: Marc Duiker <marcduiker@users.noreply.github.com>
2025-07-10 09:15:57 +01:00
Mike Nguyen 06ea44e8d3
fix: refactor log formatting (#285)
* fix: refactor log formatting

Signed-off-by: mikeee <hey@mike.ee>

* fix: refactor all print formatting

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
2025-06-27 14:56:05 +01:00
Mike Nguyen 942263938a
fix(chore): allow large size difference between variants in generated enums (#283)
Signed-off-by: Mike Nguyen <hey@mike.ee>
2025-06-03 16:16:31 +01:00
Mike Nguyen 9537a3b826
chore: limit the visibility of the cargo token (#280)
Addresses #218

Signed-off-by: Mike Nguyen <hey@mike.ee>
2025-05-14 15:49:35 +01:00
Mike Nguyen 35930ebc5f
docs: fix typo (#279)
Signed-off-by: Mike Nguyen <hey@mike.ee>
2025-05-14 13:56:31 +01:00
Mike Nguyen acb829cdb5
chore: pin idna_adapter (#278)
Signed-off-by: Mike Nguyen <hey@mike.ee>
2025-05-14 13:04:17 +01:00
Mike Nguyen 26f4ee6d32
fix(docs): over indented docs (#274)
Signed-off-by: Mike Nguyen <hey@mike.ee>
2025-04-09 11:04:09 +01:00
Mike Nguyen 4fb85abcea fix(deps): pin reserve-port to 2.1.0
Signed-off-by: Mike Nguyen <hey@mike.ee>
2025-04-01 19:19:07 +01:00
Mike Nguyen f1e469cf57 fix(deps): pin axum-test crate to 16.4.0
Signed-off-by: Mike Nguyen <hey@mike.ee>
2025-04-01 19:19:07 +01:00
Mike Nguyen 1cdcc272ce chore: remove pinned release versions validation (#270)
Signed-off-by: Mike Nguyen <hey@mike.ee>
2025-03-10 15:53:52 +00:00
Mike Nguyen 185dc72889
release: v0.16.0 (#266)
Signed-off-by: Mike Nguyen <hey@mike.ee>
2025-02-27 19:00:39 +00:00
Mike Nguyen 1508ea24cb
chore: bump protos to rc18 (#265)
Signed-off-by: Mike Nguyen <hey@mike.ee>
2025-02-27 13:47:18 +00:00
Mike Nguyen 99d099f15e
release: rc.7 (#264)
Signed-off-by: Mike Nguyen <hey@mike.ee>
2025-02-27 13:17:39 +00:00
Mike Nguyen c0b7155093
fix(deps): pin indirect dependencies (#263)
Signed-off-by: Mike Nguyen <hey@mike.ee>
2025-02-27 13:05:28 +00:00
Mike Nguyen ab219049a4
refactor(conversations): rename message to content (#261)
Signed-off-by: Mike Nguyen <hey@mike.ee>
2025-02-24 17:40:04 +00:00
Mike Nguyen 57347e70c3
feat(client): add a client port override method (#259)
* feat(client): add a client port override method

Signed-off-by: Mike Nguyen <hey@mike.ee>

* chore(lint): cargo fmt

Signed-off-by: Mike Nguyen <hey@mike.ee>

* doc(client): add port method

Signed-off-by: mikeee <hey@mike.ee>

* release: rc6

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: Mike Nguyen <hey@mike.ee>
Signed-off-by: mikeee <hey@mike.ee>
2025-02-09 21:01:22 +00:00
Mike Nguyen 93322c0e86
release: bump (#256)
* release: bump

Signed-off-by: Mike Nguyen <hey@mike.ee>

* bump to cli rc3 & runtime rc6

Signed-off-by: Mike Nguyen <hey@mike.ee>

* bump runtime to rc7

Signed-off-by: Mike Nguyen <hey@mike.ee>

* chore: bump validation to latest rcs

Signed-off-by: mikeee <hey@mike.ee>

* chore(release): bump deps and rc version

Signed-off-by: mikeee <hey@mike.ee>

* chore(release): regen protos

Signed-off-by: mikeee <hey@mike.ee>

* chore: regen protos from rc.9

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: Mike Nguyen <hey@mike.ee>
Signed-off-by: mikeee <hey@mike.ee>
2025-02-03 15:49:18 +00:00
Leon Matthes 52f095f8e7
Add fallback handler to axum Router (#258)
By default the fallback handler now logs the path that could not be
found.
This can be vital for debugging, as otherwise there is no feedback on
the server if a method is called that isn't registered.

Signed-off-by: Leon Matthes <leon.matthes@kdab.com>
2025-01-28 20:21:14 +00:00
Mike Nguyen a532ee1a50
chore: bump runtime to 1.15.0-rc.2 (#255)
Signed-off-by: mikeee <hey@mike.ee>
2025-01-15 16:12:31 +00:00
Mike Nguyen 8bf6013eee
Cleanup (#254)
* Return Result when creating DaprHttpServer

Especially when running custom docker setups, the container that
contains the sidecar may not be running exactly when the Rust code
starts running.

To fix this, before we needed to sleep(2s) to avoid a panic in the Rust
program.
With this patch, this can be handled on the user side (e.g. the
connection can be retried multiple times with timeouts in-between).

Signed-off-by: Leon Matthes <leon.matthes@kdab.com>

* release: v0.16.0-rc.4

Signed-off-by: Mike Nguyen <hey@mike.ee>

* chore(deps): remove unused crates

Signed-off-by: Mike Nguyen <hey@mike.ee>

* doc: missing expression closure

Signed-off-by: Mike Nguyen <hey@mike.ee>

* refactor: lint issues and correctness improvements

Signed-off-by: Mike Nguyen <hey@mike.ee>

---------

Signed-off-by: Leon Matthes <leon.matthes@kdab.com>
Signed-off-by: Mike Nguyen <hey@mike.ee>
Co-authored-by: Leon Matthes <leon.matthes@kdab.com>
2025-01-15 10:52:01 +00:00
Leon Matthes 6973b7d9be
Return Result when creating DaprHttpServer (#253)
Especially when running custom docker setups, the container that
contains the sidecar may not be running exactly when the Rust code
starts running.

With this patch, this can be handled on the user side (e.g. the
connection can be retried multiple times with timeouts in between).

Signed-off-by: Leon Matthes <leon.matthes@kdab.com>
Co-authored-by: Mike Nguyen <hey@mike.ee>
2024-12-10 20:16:13 +00:00
Mike Nguyen 5241ce696c
Merge pull request #251 from mikeee/docs
docs: clarify and fix mistakes
2024-12-03 11:54:06 +00:00
Mike Nguyen 2deed2baa8
Merge pull request #252 from mikeee/proto-update
chore: bump protos to 1.15.0-rc.1 tag
2024-12-03 11:53:47 +00:00
Mike Nguyen b9de85f885
chore: bump protos to 1.15.0-rc.1 tag
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-12-03 10:22:41 +00:00
Mike Nguyen 0c909c544b
docs: clarify and fix mistakes
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-12-03 10:14:04 +00:00
Mike Nguyen f0498dcc3f
Merge pull request #250 from mikeee/dry-publish
ci: add dry publish test
2024-11-25 18:01:04 +00:00
Mike Nguyen abecc5c70b
ci: add dry publish test
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-25 17:43:37 +00:00
Mike Nguyen 4da565cbae
Merge pull request #249 from mikeee/rm-macro-dep
chore: remove macro dep from main crate
2024-11-25 17:42:43 +00:00
Mike Nguyen 1d88e2074f
Merge branch 'release-0.16' into rm-macro-dep 2024-11-25 17:35:26 +00:00
Mike Nguyen 1ac019159c
Merge pull request #248 from mikeee/check-proto-diff
feat: add proto check and make directives
2024-11-25 17:35:11 +00:00
Mike Nguyen c4675a6a09
Merge branch 'release-0.16' into check-proto-diff 2024-11-25 17:22:53 +00:00
Mike Nguyen 85ed911b1d
chore: add macro dev-dependency and bump axum-test crate version
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-25 16:50:40 +00:00
Mike Nguyen 95b009baaf
chore: remove macro dep from main crate
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-25 16:20:17 +00:00
Mike Nguyen e15f65b435
ci: refactor doc test
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-25 15:51:58 +00:00
Mike Nguyen fcff470451
Merge pull request #247 from mikeee/rc3
chore: bump rc versions
2024-11-25 15:47:41 +00:00
Mike Nguyen ae9bcda712
ci: rename steps
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-25 15:43:05 +00:00
Mike Nguyen 851abcae57
feat: add proto check and make directives
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-25 15:33:55 +00:00
Mike Nguyen b2be904225
chore: bump rc versions
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-25 14:51:44 +00:00
Mike Nguyen 4cfa9a3db2
Merge pull request #245 from mikeee/dapr-docs
Update Dapr Rust docs
2024-11-25 12:02:10 +00:00
Mike Nguyen e78cab477e
Merge branch 'release-0.16' into dapr-docs
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-25 11:48:31 +00:00
Mike Nguyen 709c67e856
Merge pull request #246 from mikeee/226-state_metadata
refactor state methods
2024-11-25 11:47:29 +00:00
Mike Nguyen b1cacef2d7
docs(state): update daprdocs
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-25 11:10:45 +00:00
Mike Nguyen 597aa46f0e
chore(lint): fmt
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-25 08:37:07 +00:00
Mike Nguyen 0183be5baa
feat(state)!: add state and bulk state methods
This includes metadata and options for storing state with etags and consistency

Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-24 20:54:53 +00:00
mikeee 580b88ff8a
docs: address #241 with updated guidance on instantiating a client
Signed-off-by: mikeee <hey@mike.ee>
2024-11-21 16:49:13 +00:00
mikeee e04157d7d7
docs: address #240 - update to 0.16.0 in anticipation of the release
Signed-off-by: mikeee <hey@mike.ee>
2024-11-21 16:38:54 +00:00
mikeee b81f8f387b
docs: fix typo
Signed-off-by: mikeee <hey@mike.ee>
2024-11-21 16:38:40 +00:00
Mike Nguyen df0bf8818c
Merge branch 'main' into release-0.16 2024-11-16 16:20:56 +00:00
Mike Nguyen 04375f4fd2
Merge pull request #234 from mikeee/conversation-api
feat: conversation api initial implementation
2024-11-07 19:29:12 +00:00
Mike Nguyen 80a3a90f82
fix(test): example validation
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-07 14:34:40 +00:00
Mike Nguyen fbb81bf518
fix(test): example run
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-07 14:19:23 +00:00
Mike Nguyen dbc7a80ef1
fix(test): close step token
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-07 13:56:28 +00:00
Mike Nguyen 12dd8af64f
Merge branch 'release-0.16' into conversation-api 2024-11-07 13:45:19 +00:00
Mike Nguyen 0f29428a55
fix(ci): fix installer bundle creation logic (#239)
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-07 13:44:45 +00:00
Mike Nguyen 981340a5d8
Merge branch 'release-0.16' into conversation-api 2024-11-07 13:00:09 +00:00
Mike Nguyen 5fd49f196f
fix(ci): fix installer bundle creation logic (#238)
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-07 12:59:47 +00:00
Mike Nguyen 7322ec4cc3
Merge branch 'release-0.16' into conversation-api 2024-11-07 12:34:12 +00:00
Mike Nguyen 8f00930ebc
fix(ci): fix installer bundle creation logic (#237)
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-07 12:33:58 +00:00
Mike Nguyen f70a18f896
Merge branch 'release-0.16' into conversation-api 2024-11-07 12:25:59 +00:00
Mike Nguyen 78ad9fd685
Merge pull request #235 from mikeee/remove-version-spaces
fix(ci): trim blank spaces from version strings
2024-11-07 12:25:20 +00:00
Mike Nguyen 01d2214a0d
fix(ci): trim blank spaces from version strings
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-07 12:20:24 +00:00
Mike Nguyen d0b6490d9c
feat: conversation api initial implementation
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-07 11:54:00 +00:00
Mike Nguyen 4e2d316032
Merge pull request #230 from dapr/release-0.16
merge Release 0.16
2024-11-04 22:08:48 +00:00
Mike Nguyen 39071997ac
chore: release versioning (#232)
* chore: release versioning

Signed-off-by: Mike Nguyen <hey@mike.ee>

* docs: update dep version

Signed-off-by: Mike Nguyen <hey@mike.ee>

---------

Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-04 17:24:21 +00:00
Mike Nguyen 97c98af9aa
fix: remove decoder step (#228)
Signed-off-by: mikeee <hey@mike.ee>
2024-11-04 17:09:28 +00:00
Mike Nguyen 1b095c7108
ci: add scheduled runs to test and validation workflows (#231)
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-04 16:52:13 +00:00
Mike Nguyen 81b3834fd7
chore: refactor deprecated method and regen protos (#229)
Signed-off-by: mikeee <hey@mike.ee>
2024-11-04 16:33:14 +00:00
Mike Nguyen 7a508beaea
docs: update proto notice (#224)
Signed-off-by: mikeee <hey@mike.ee>
2024-08-21 12:52:53 +01:00
Mike Nguyen 0a0efaa9ab
chore(release): update version (#223)
Signed-off-by: mikeee <hey@mike.ee>
2024-08-20 20:03:02 +01:00
Mike Nguyen 6f566cb051
fix: release fixes (#222)
* fix: release fixes

Signed-off-by: mikeee <hey@mike.ee>

* fix: refactor path and add absolute examples url

Signed-off-by: mikeee <hey@mike.ee>

* fix: add dapr dev dep

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
2024-08-20 19:58:48 +01:00
Mike Nguyen 8d4db4382c
chore(release): v0.16.0-rc.0 (#221)
Signed-off-by: mikeee <hey@mike.ee>
2024-08-20 19:30:36 +01:00
Mike Nguyen ece8714f29
ci(docs): add docs job (#220)
* ci(docs): add docs checking workflow

Signed-off-by: mikeee <hey@mike.ee>

* fix(ci): remove override toolchain

Signed-off-by: mikeee <hey@mike.ee>

* docs: fix warnings and regen protos

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
2024-08-20 19:14:34 +01:00
Mike Nguyen 60c0bbed71
chore(deps): upgrade deps and regen protos (#214)
* chore(deps): upgrade deps and regen protos

Signed-off-by: mikeee <hey@mike.ee>

* refactor(deps): use workspaces and consolidate deps

Signed-off-by: mikeee <hey@mike.ee>

* fix: add log dep

Signed-off-by: mikeee <hey@mike.ee>

* ci: add stable, nightly and msrv 1.70.0

Signed-off-by: mikeee <hey@mike.ee>

* fix: remove unused import

Signed-off-by: mikeee <hey@mike.ee>

* ci: disable failfast

Signed-off-by: mikeee <hey@mike.ee>

* docs: fix missing annotation and docs codeblock

Signed-off-by: mikeee <hey@mike.ee>

* chore(msrv): set msrv to 1.78 and increase coverage

Signed-off-by: mikeee <hey@mike.ee>

* docs: update msrv

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
2024-08-20 18:21:18 +01:00
Mike Nguyen 0eaf89867c
fix: include scheduler host address (#217)
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-08-20 12:28:19 +01:00
Mike Nguyen ccf2902ed5
refactor: deny warnings (#215)
* ci: deny warnings

Signed-off-by: mikeee <hey@mike.ee>

* refactor: remove redundant type conversions

Signed-off-by: mikeee <hey@mike.ee>

* ci: remove clippy flag

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
2024-08-20 08:29:26 +01:00
Mike Nguyen 2c0aa5a779
ci - fixing warnings (#211)
* ci: disable caching and conditionally set up go

Signed-off-by: mikeee <hey@mike.ee>

* ci: update actions/checkout to v4 and locks fossa to v1

Signed-off-by: mikeee <hey@mike.ee>

* ci: fix typo

Signed-off-by: mikeee <hey@mike.ee>

* chore: update ignores to all targets

Signed-off-by: mikeee <hey@mike.ee>

* ci: migrate rust action, auth protoc setup, build examples and proto-gen

Signed-off-by: mikeee <hey@mike.ee>

* fix: change branch name reference to master

Signed-off-by: mikeee <hey@mike.ee>

* ci: bump setup-protoc to v3

Signed-off-by: mikeee <hey@mike.ee>

* ci: install protoc pinned 24.4

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
2024-08-19 16:15:05 +01:00
Mike Nguyen 5e699df5a3
doc changes and updates related to proto-gen and examples (#210)
* fix: update documentation and proto script

Signed-off-by: mikeee <hey@mike.ee>

* docs: add missing closure

Signed-off-by: mikeee <hey@mike.ee>

* chore: exclude proto-gen and examples

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
2024-08-19 13:11:37 +01:00
Mike Nguyen 6301ee43c5
refactor!: dapr no longer requires protoc or tonic_build (#206)
* refactor!: dapr no longer requires protoc or tonic_build
The dapr crate no longer requires tonic_build or protoc to build.
The examples have been moved into a separate crate.
proto-gen is now compiling the dapr and example protos.

Signed-off-by: mikeee <hey@mike.ee>

* chore: fmt run

Signed-off-by: mikeee <hey@mike.ee>

* chore: update example names

Signed-off-by: mikeee <hey@mike.ee>

* fix: add a build step

Signed-off-by: mikeee <hey@mike.ee>

* test: remove ci build step and add it to the examples

Signed-off-by: mikeee <hey@mike.ee>

* fix: update validation workflows

Signed-off-by: mikeee <hey@mike.ee>

* tests: tweaks to timings

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
2024-08-19 12:44:18 +01:00
Mike Nguyen 7aef43a7b4
docs: fix comments (#204)
Signed-off-by: mikeee <hey@mike.ee>
2024-08-15 20:15:05 +01:00
Mike Nguyen 6951e58060
ci: explicitly authenticate protoc setup step (#203)
Also adds a baseline scope to the tokens - packages already is a default read-only option for the token.

Signed-off-by: mikeee <hey@mike.ee>
2024-08-15 14:40:41 +01:00
Mike Nguyen bc728d5262
docs: update versions (#202)
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-08-14 11:48:33 +01:00
102 changed files with 9984 additions and 507 deletions

View File

@ -1,6 +1,8 @@
name: dapr-rust-sdk name: dapr-rust-sdk
on: on:
schedule:
- cron: '8 8 * * *'
push: push:
branches: branches:
- main - main
@ -14,75 +16,134 @@ on:
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
CARGO_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} PROTOC_VERSION: 24.4
PROTOC_VERSION: 3.x RUSTFLAGS: "-D warnings"
RUST_TOOLCHAIN: 1.79.0
jobs: jobs:
lint: lint:
name: Lint name: Check and Lint
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Install Rust Toolchain - name: Install Rust
uses: actions-rs/toolchain@v1 uses: dtolnay/rust-toolchain@master
with: with:
toolchain: ${{ env.RUST_TOOLCHAIN }} toolchain: stable
override: true components: clippy, rustfmt
components: rustfmt, clippy
- name: Install Protoc - name: Install Protoc
uses: arduino/setup-protoc@v1 uses: arduino/setup-protoc@v3
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
version: ${{ env.PROTOC_VERSION }} version: ${{ env.PROTOC_VERSION }}
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Check compiled protos for a diff
run: |
make proto-gen check-diff-proto
- name: cargo fmt - name: cargo fmt
run: cargo fmt -- --check --color ${{ env.CARGO_TERM_COLOR }} run: cargo fmt -- --check --color ${{ env.CARGO_TERM_COLOR }}
- name: cargo clippy - name: cargo clippy
run: cargo clippy -- -W warnings run: cargo clippy
build: build:
name: Build name: Test and Build on rust-${{ matrix.rust-version }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
rust-version:
- "stable"
- "nightly"
- "1.78.0" # MSRV
steps: steps:
- name: Install Rust Toolchain - name: Install Rust
uses: actions-rs/toolchain@v1 uses: dtolnay/rust-toolchain@master
with: with:
toolchain: ${{ env.RUST_TOOLCHAIN }} toolchain: ${{ matrix.rust-version }}
override: true components: clippy, rustfmt
components: rustfmt, clippy
- name: Install Protoc - name: Install Protoc
uses: arduino/setup-protoc@v1 uses: arduino/setup-protoc@v3
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
version: ${{ env.PROTOC_VERSION }} version: ${{ env.PROTOC_VERSION }}
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Build - name: Build
run: cargo build run: cargo build --workspace --all-targets --all-features
- name: Build examples
run: cargo build --examples
- name: Run Tests - name: Run Tests
run: cargo test --all-targets run: cargo test --workspace --all-targets --all-features
test-docs:
name: Check Docs - ${{ matrix.crate }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
crate:
- dapr
- dapr-macros
env:
RUSTDOCFLAGS: -Dwarnings
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- uses: dtolnay/install@cargo-docs-rs
- run: cargo docs-rs -p ${{ matrix.crate }}
publish-dry:
name: Publish Test
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
crate:
- dapr
- dapr-macros
steps:
- name: Install Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
components: clippy, rustfmt
- name: Install Protoc
uses: arduino/setup-protoc@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
version: ${{ env.PROTOC_VERSION }}
- uses: actions/checkout@v4
- name: cargo publish - ${{ matrix.crate }}
run: cargo publish --manifest-path ${{ matrix.crate }}/Cargo.toml --dry-run
publish: publish:
name: Publish name: Publish
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [lint, build] needs: [test-docs, lint, build, publish-dry]
if: startswith(github.ref, 'refs/tags/v') if: startswith(github.ref, 'refs/tags/v')
strategy:
fail-fast: false
matrix:
crate:
- dapr
- dapr-macros
steps: steps:
- name: Install Rust Toolchain - name: Install Rust
uses: actions-rs/toolchain@v1 uses: dtolnay/rust-toolchain@master
with: with:
toolchain: ${{ env.RUST_TOOLCHAIN }} toolchain: stable
override: true components: clippy, rustfmt
components: rustfmt, clippy
- name: Install Protoc - name: Install Protoc
uses: arduino/setup-protoc@v1 uses: arduino/setup-protoc@v3
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
version: ${{ env.PROTOC_VERSION }} version: ${{ env.PROTOC_VERSION }}
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: cargo publish macros - name: cargo publish - ${{ matrix.crate }}
run: cargo publish --manifest-path macros/Cargo.toml --token ${{ env.CARGO_TOKEN }} env:
- name: cargo publish CARGO_TOKEN: ${{ secrets.CARGO_TOKEN }}
run: cargo publish --token ${{ env.CARGO_TOKEN }} run: cargo publish --manifest-path ${{ matrix.crate }}/Cargo.toml --token ${{ env.CARGO_TOKEN }}

View File

@ -1,15 +1,16 @@
[package] [package]
name = "dapr-bot" name = "dapr-bot"
authors = ["hey@mike.ee"] authors = ["Mike Nguyen <hey@mike.ee>"]
license = "Apache-2.0"
license-file = "LICENSE" license-file = "LICENSE"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
rust-version = "1.70.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
exitcode = "1.1.2" exitcode = "1.1.2"
octocrab = "0.34.1" octocrab = "0.42.1"
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.114" serde_json = "1.0.114"
tokio = { version = "1.36.0", features = ["full"] } tokio = { version = "1.36.0", features = ["full"] }

View File

@ -32,15 +32,15 @@ jobs:
FOSSA_API_KEY: b88e1f4287c3108c8751bf106fb46db6 # This is a push-only token that is safe to be exposed. FOSSA_API_KEY: b88e1f4287c3108c8751bf106fb46db6 # This is a push-only token that is safe to be exposed.
steps: steps:
- name: "Checkout code" - name: "Checkout code"
uses: actions/checkout@v2 uses: actions/checkout@v4
- name: "Run FOSSA Scan" - name: "Run FOSSA Scan"
uses: fossas/fossa-action@main # Use a specific version if locking is preferred uses: fossas/fossa-action@v1 # Use a specific version if locking is preferred
with: with:
api-key: ${{ env.FOSSA_API_KEY }} api-key: ${{ env.FOSSA_API_KEY }}
- name: "Run FOSSA Test" - name: "Run FOSSA Test"
uses: fossas/fossa-action@main # Use a specific version if locking is preferred uses: fossas/fossa-action@v1 # Use a specific version if locking is preferred
with: with:
api-key: ${{ env.FOSSA_API_KEY }} api-key: ${{ env.FOSSA_API_KEY }}
run-tests: true run-tests: true

View File

@ -1,6 +1,8 @@
name: validate-examples name: validate-examples
on: on:
schedule:
- cron: '8 8 * * *'
push: push:
branches: branches:
- main - main
@ -34,6 +36,8 @@ on:
merge_group: merge_group:
jobs: jobs:
setup: setup:
permissions:
packages: read
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
GOOS: linux GOOS: linux
@ -69,11 +73,6 @@ jobs:
repository: ${{ env.CHECKOUT_REPO }} repository: ${{ env.CHECKOUT_REPO }}
ref: ${{ env.CHECKOUT_REF }} ref: ${{ env.CHECKOUT_REF }}
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "stable"
- name: Determine latest Dapr Runtime version - name: Determine latest Dapr Runtime version
if: env.DAPR_RUNTIME_VERSION == '' if: env.DAPR_RUNTIME_VERSION == ''
run: | run: |
@ -104,6 +103,13 @@ jobs:
ref: ${{ env.DAPR_REF }} ref: ${{ env.DAPR_REF }}
path: dapr_runtime path: dapr_runtime
- name: Set up Go
uses: actions/setup-go@v5
if: env.DAPR_REF != '' || env.DAPR_CLI_REF != ''
with:
cache: false
go-version: "stable"
- name: Build dapr cli with referenced commit and override version - name: Build dapr cli with referenced commit and override version
if: env.DAPR_CLI_REF != '' if: env.DAPR_CLI_REF != ''
run: | run: |
@ -121,6 +127,7 @@ jobs:
cd dapr_runtime cd dapr_runtime
make make
echo "artifactPath=~/artifacts/$GITHUB_SHA/" >> $GITHUB_ENV echo "artifactPath=~/artifacts/$GITHUB_SHA/" >> $GITHUB_ENV
mkdir -p $HOME/artifacts/$GITHUB_SHA/
RUNTIME_VERSION=edge RUNTIME_VERSION=edge
echo "DAPR_RUNTIME_VERSION=$RUNTIME_VERSION" >> $GITHUB_ENV echo "DAPR_RUNTIME_VERSION=$RUNTIME_VERSION" >> $GITHUB_ENV
@ -129,7 +136,7 @@ jobs:
run: | run: |
mkdir ~/dapr_docker mkdir ~/dapr_docker
cd dapr_runtime cd dapr_runtime
docker build --build-arg "PKG_FILES=*" -f ./docker/Dockerfile ./dist/linux_amd64/release -t daprio/dapr:0.0.0-dev docker build --build-arg "PKG_FILES=*" -f ./docker/Dockerfile ./dist/linux_amd64/release -t daprio/dapr:9.0.0-dev
- name: Download Install Bundle CLI - name: Download Install Bundle CLI
if: env.DAPR_REF != '' && env.DAPR_CLI_REF == '' if: env.DAPR_REF != '' && env.DAPR_CLI_REF == ''
@ -141,14 +148,14 @@ jobs:
ls -la ls -la
- name: Build Custom Install Bundle - name: Build Custom Install Bundle
if: env.DAPR_REF != '' && env.DAPR_CLI_REF != '' if: env.DAPR_REF != '' || env.DAPR_CLI_REF != ''
run: | run: |
: # Create daprbundle directory : # Create daprbundle directory
mkdir ~/daprbundle mkdir ~/daprbundle
cp .github/workflows/validate-examples/details.json ~/daprbundle/ cp .github/workflows/validate-examples/details.json ~/daprbundle/
: # Add cli : # Add cli
cp ~/artifacts/$GITHUB_SHA/dapr ~/daprbundle/dapr cp cli/dist/linux_amd64/release/dapr ~/daprbundle/dapr
: # Compress executables to /dist/ appending _linux_amd64 to the name : # Compress executables to /dist/ appending _linux_amd64 to the name
mkdir ~/daprbundle/dist mkdir ~/daprbundle/dist
@ -163,7 +170,7 @@ jobs:
: # Add docker image : # Add docker image
mkdir ~/daprbundle/docker mkdir ~/daprbundle/docker
docker save daprio/dapr:0.0.0-dev | gzip > ~/daprbundle/docker/daprio-dapr-0.0.0-dev.tar.gz docker save daprio/dapr:9.0.0-dev | gzip > ~/daprbundle/docker/daprio-dapr-9.0.0-dev.tar.gz
: # Bundle : # Bundle
cd ~/daprbundle cd ~/daprbundle
@ -195,6 +202,8 @@ jobs:
echo "GITHUB_SHA=$GITHUB_SHA" >> "$GITHUB_OUTPUT" echo "GITHUB_SHA=$GITHUB_SHA" >> "$GITHUB_OUTPUT"
validate-example: validate-example:
permissions:
packages: read
needs: setup needs: setup
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
@ -211,7 +220,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
examples: examples:
[ "actors", "bindings", "client", "configuration", "crypto", "invoke/grpc", "invoke/grpc-proxying", "jobs", "pubsub", "query_state", "secrets-bulk" ] [ "actors", "bindings", "client", "configuration", "conversation", "crypto", "invoke/grpc", "invoke/grpc-proxying", "jobs", "pubsub", "query_state", "secrets-bulk" ]
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@v4 uses: actions/checkout@v4
@ -242,7 +251,8 @@ jobs:
- name: Install Protoc - name: Install Protoc
uses: arduino/setup-protoc@v3 uses: arduino/setup-protoc@v3
with: with:
version: "25.2" version: "24.4"
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Dapr CLI ${{ env.DAPR_CLI_VERSION }} - name: Set up Dapr CLI ${{ env.DAPR_CLI_VERSION }}
if: env.DAPR_CLI_VERSION != 'edge' if: env.DAPR_CLI_VERSION != 'edge'
@ -289,9 +299,6 @@ jobs:
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install mechanical-markdown pip install mechanical-markdown
- name: Cargo Build Examples
run: cargo build --examples
- name: Dapr version - name: Dapr version
run: | run: |
dapr version dapr version

View File

@ -1,9 +1,9 @@
{ {
"daprd": "0.0.0-dev", "daprd": "9.0.0-dev",
"dashboard": "0.0.0-dev", "dashboard": "9.0.0-dev",
"cli": "0.0.0-dev", "cli": "9.0.0-dev",
"daprBinarySubDir": "dist", "daprBinarySubDir": "dist",
"dockerImageSubDir": "docker", "dockerImageSubDir": "docker",
"daprImageName": "daprio/dapr:0.0.0-dev", "daprImageName": "daprio/dapr:9.0.0-dev",
"daprImageFileName": "daprio-dapr-0.0.0-dev.tar.gz" "daprImageFileName": "daprio-dapr-9.0.0-dev.tar.gz"
} }

2
.gitignore vendored
View File

@ -1,6 +1,6 @@
# Generated by Cargo # Generated by Cargo
# will have compiled files and executables # will have compiled files and executables
/target/ target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html

View File

@ -1,108 +1,38 @@
[package] [workspace]
name = "dapr" members = [
version = "0.15.0" "dapr",
authors = ["dapr.io"] "dapr-macros",
"proto-gen",
"examples",
]
exclude = [
".github/workflows/dapr-bot" # Bot used in GitHub workflow
]
resolver = "2"
[workspace.dependencies]
async-trait = "0.1"
prost = "0.13.4"
prost-types = "0.13.4"
serde = "1.0"
serde_json = "1.0"
tokio = "1.39"
tokio-stream = "0.1"
tokio-util = "0.7"
tonic = "0.12.3"
tonic-build = "0.12.3"
[workspace.package]
version = "0.16.0"
authors = [
"Mike Nguyen <hey@mike.ee>",
"The Dapr Authors <dapr@dapr.io>"
]
edition = "2021" edition = "2021"
license = "Apache-2.0" license = "Apache-2.0"
repository = "https://github.com/dapr/rust-sdk" repository = "https://github.com/dapr/rust-sdk"
description = "Rust SDK for dapr"
readme = "README.md"
keywords = ["microservices", "dapr"]
[dependencies] rust-version = "1.78.0" # MSRV
dapr-macros = { version = "0.15.0", path = "macros" }
futures = "0.3"
tonic = "0.11.0"
prost = "0.12.3"
bytes = "1"
prost-types = "0.12.3"
async-trait = "0.1"
env_logger = "0.11.2"
log = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
axum = "0.7.4"
tokio = { version = "1.29", features = ["sync"] }
tokio-util = { version = "0.7.10", features = ["io"] }
chrono = "0.4.38"
base64 = "0.22.1"
[build-dependencies]
tonic-build = "0.11.0"
[dev-dependencies]
axum-test = "15.0.1"
once_cell = "1.18.0"
tokio = { version = "1", features = ["full"] }
uuid = { version = "1.4.0", features = ["v4"] }
dapr = { path = "./" }
tokio-test = "0.4.2"
tokio-stream = { version = "0.1" }
[[example]]
name = "actor-client"
path = "examples/actors/client.rs"
[[example]]
name = "actor-server"
path = "examples/actors/server.rs"
[[example]]
name = "client"
path = "examples/client/client.rs"
[[example]]
name = "configuration"
path = "examples/configuration/main.rs"
[[example]]
name = "crypto"
path = "examples/crypto/main.rs"
[[example]]
name = "invoke-grpc-client"
path = "examples/invoke/grpc/client.rs"
[[example]]
name = "invoke-grpc-server"
path = "examples/invoke/grpc/server.rs"
[[example]]
name = "invoke-grpc-proxying-client"
path = "examples/invoke/grpc-proxying/client.rs"
[[example]]
name = "invoke-grpc-proxying-server"
path = "examples/invoke/grpc-proxying/server.rs"
[[example]]
name = "jobs"
path = "examples/jobs/jobs.rs"
[[example]]
name = "publisher"
path = "examples/pubsub/publisher.rs"
[[example]]
name = "subscriber"
path = "examples/pubsub/subscriber.rs"
[[example]]
name = "output-bindings"
path = "examples/bindings/output.rs"
[[example]]
name = "input-bindings"
path = "examples/bindings/input.rs"
[[example]]
name = "query_state_q1"
path = "examples/query_state/query1.rs"
[[example]]
name = "query_state_q2"
path = "examples/query_state/query2.rs"
[[example]]
name = "secrets-bulk"
path = "examples/secrets-bulk/app.rs"

7
Makefile Normal file
View File

@ -0,0 +1,7 @@
.PHONY: proto-gen
proto-gen:
cargo run --bin proto-gen
.PHONY: check-diff-proto
check-diff-proto:
git diff --exit-code ./proto/

View File

@ -43,9 +43,9 @@ resiliency.
## Prerequisites ## Prerequisites
Ensure you have Rust version 1.79 or higher installed. If not, install Rust [here](https://www.rust-lang.org/tools/install). Ensure you have Rust version 1.78 or higher installed. If not, install Rust [here](https://www.rust-lang.org/tools/install).
You will also need to install [protoc](https://github.com/protocolbuffers/protobuf#protobuf-compiler-installation). These crates no longer require protoc unless to recompile the protobuf files.
## How to use ## How to use
@ -53,14 +53,15 @@ Add the following to your `Cargo.toml` file:
```toml ```toml
[dependencies] [dependencies]
dapr = "0.13.0" dapr = "0.16.0"
``` ```
Here's a basic example to create a client: Here's a basic example to create a client:
```rust ```Rust
use dapr; use dapr;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Get the Dapr port and create a connection // Get the Dapr port and create a connection
let port: u16 = std::env::var("DAPR_GRPC_PORT")?.parse()?; let port: u16 = std::env::var("DAPR_GRPC_PORT")?.parse()?;
@ -68,11 +69,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create the client // Create the client
let mut client = dapr::Client::<dapr::client::TonicClient>::connect(addr).await?; let mut client = dapr::Client::<dapr::client::TonicClient>::connect(addr).await?;
}
``` ```
## Explore more examples ## Explore more examples
Browse through more examples to understand the SDK better: [View examples](./examples) Browse through more examples to understand the SDK better: [View examples](https://github.com/dapr/rust-sdk/tree/main/examples)
## Building ## Building
@ -82,9 +84,7 @@ To build the SDK run:
cargo build cargo build
``` ```
>Note: The protobuf client generation is built into `cargo build` process so updating the proto files under `dapr/` is enough to update the protobuf client. ## Developing (Updating .proto files from upstream Dapr)
## Updating .proto files from upstream Dapr
To fetch the latest .proto files from Dapr execute the script `update-protos.sh`: To fetch the latest .proto files from Dapr execute the script `update-protos.sh`:
@ -95,7 +95,15 @@ To fetch the latest .proto files from Dapr execute the script `update-protos.sh`
By default, the script fetches the latest proto updates from the master branch of the Dapr repository. If you need to choose a specific release or version, use the -v flag: By default, the script fetches the latest proto updates from the master branch of the Dapr repository. If you need to choose a specific release or version, use the -v flag:
```bash ```bash
./update-protos.sh -v v1.12.0 ./update-protos.sh -v v1.14.0
```
You will also need to install [protoc](https://github.com/protocolbuffers/protobuf#protobuf-compiler-installation).
Protos can then be compiled using:
```bash
cargo run proto-gen
``` ```
### Contact Us ### Contact Us

View File

@ -1,15 +0,0 @@
// use std::env;
fn main() -> Result<(), std::io::Error> {
// env::set_var("OUT_DIR", "src");
tonic_build::configure().build_server(true).compile(
&[
"dapr/proto/common/v1/common.proto",
"dapr/proto/runtime/v1/dapr.proto",
"dapr/proto/runtime/v1/appcallback.proto",
"examples/invoke/proto/helloworld.proto",
],
&["."],
)?;
Ok(())
}

17
dapr-macros/Cargo.toml Normal file
View File

@ -0,0 +1,17 @@
[package]
name = "dapr-macros"
version.workspace = true
authors.workspace = true
edition.workspace = true
description = "Dapr Rust SDK (Macros)"
license.workspace = true
repository.workspace = true
rust-version.workspace = true
[lib]
proc-macro = true
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "2.0", features = ["full"] }

View File

@ -1,10 +1,11 @@
use proc_macro::TokenStream;
use std::iter; use std::iter;
use proc_macro2::TokenTree; use proc_macro2::TokenTree;
use quote::{format_ident, quote}; use quote::{format_ident, quote};
use syn::{Ident, LitStr, parse_macro_input};
use syn::parse::{Parse, ParseStream}; use syn::parse::{Parse, ParseStream};
use syn::{parse_macro_input, Ident, LitStr};
use proc_macro::TokenStream;
macro_rules! derive_parse {( macro_rules! derive_parse {(
@derive_only @derive_only
@ -80,7 +81,7 @@ pub fn actor(_attr: TokenStream, item: TokenStream) -> TokenStream {
Ok(actor_struct) => actor_struct.ident.clone(), Ok(actor_struct) => actor_struct.ident.clone(),
Err(_) => match syn::parse::<syn::ItemType>(item.clone()) { Err(_) => match syn::parse::<syn::ItemType>(item.clone()) {
Ok(ty) => ty.ident.clone(), Ok(ty) => ty.ident.clone(),
Err(e) => panic!("Error parsing actor struct: {}", e), Err(e) => panic!("Error parsing actor struct: {e}"),
}, },
}; };
@ -152,7 +153,6 @@ pub fn topic(args: TokenStream, input: TokenStream) -> TokenStream {
let struct_name = name let struct_name = name
.to_string() .to_string()
.split('_') .split('_')
.into_iter()
.map(|i| { .map(|i| {
let mut chars: Vec<char> = i.chars().collect(); let mut chars: Vec<char> = i.chars().collect();
chars[0] = chars[0].to_ascii_uppercase(); chars[0] = chars[0].to_ascii_uppercase();
@ -172,7 +172,6 @@ pub fn topic(args: TokenStream, input: TokenStream) -> TokenStream {
.to_string() .to_string()
.replace(['(', ')'], "") .replace(['(', ')'], "")
.split(':') .split(':')
.into_iter()
.enumerate() .enumerate()
.filter(|&(i, _)| i % 2 != 0) .filter(|&(i, _)| i % 2 != 0)
.map(|(_, i)| i.trim().to_string()) .map(|(_, i)| i.trim().to_string())

40
dapr/Cargo.toml Normal file
View File

@ -0,0 +1,40 @@
[package]
name = "dapr"
version.workspace = true
authors.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
description = "Rust SDK for dapr"
readme = "README.md"
keywords = ["microservices", "dapr"]
rust-version.workspace = true
[dependencies]
async-trait = { workspace = true }
axum = "0.7"
chrono = "0.4"
futures = "0.3"
log = "0.4"
prost = { workspace = true }
prost-types = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
tonic = { workspace = true }
tokio = { workspace = true, features = ["sync"] }
tokio-util = { workspace = true, features = ["io"] }
[dev-dependencies]
axum-test = "=16.4.0" # TODO: Remove problematic dep
litemap = "=0.7.4" # TODO: Remove pinned - linked to axum_test
zerofrom = "=0.1.5" # TODO: Remove pinned - linked to axum_test
reserve-port = "=2.1.0" # TODO: Remove pinned - linked to axum_test
idna_adapter = "=1.2.0"
once_cell = "1.19"
dapr = { path = "./" }
dapr-macros = { path = "../dapr-macros" }
tokio = { workspace = true, features = ["full"] }
uuid = { version = "1.10", features = ["v4"] }
tokio-stream = { workspace = true }

1
dapr/README.md Symbolic link
View File

@ -0,0 +1 @@
../README.md

View File

@ -1,38 +1,36 @@
use crate::dapr::proto::runtime::v1::app_callback_server::AppCallback;
use crate::dapr::proto::{common, runtime};
use std::collections::HashMap; use std::collections::HashMap;
use tonic::{Code, Request, Response, Status}; use tonic::{Code, Request, Response, Status};
use crate::dapr::dapr::proto::runtime::v1::app_callback_server::AppCallback;
use crate::dapr::dapr::proto::{common, runtime};
use crate::dapr::*;
/// InvokeRequest is the message to invoke a method with the data. /// InvokeRequest is the message to invoke a method with the data.
pub type InvokeRequest = dapr::proto::common::v1::InvokeRequest; pub type InvokeRequest = common::v1::InvokeRequest;
/// InvokeResponse is the response message inclduing data and its content type /// InvokeResponse is the response message inclduing data and its content type
/// from app callback. /// from app callback.
pub type InvokeResponse = dapr::proto::common::v1::InvokeResponse; pub type InvokeResponse = common::v1::InvokeResponse;
/// ListTopicSubscriptionsResponse is the message including the list of the subscribing topics. /// ListTopicSubscriptionsResponse is the message including the list of the subscribing topics.
pub type ListTopicSubscriptionsResponse = dapr::proto::runtime::v1::ListTopicSubscriptionsResponse; pub type ListTopicSubscriptionsResponse = runtime::v1::ListTopicSubscriptionsResponse;
/// TopicSubscription represents a topic and it's metadata (session id etc.) /// TopicSubscription represents a topic and it's metadata (session id etc.)
pub type TopicSubscription = dapr::proto::runtime::v1::TopicSubscription; pub type TopicSubscription = runtime::v1::TopicSubscription;
/// TopicEventRequest message is compatiable with CloudEvent spec v1.0. /// TopicEventRequest message is compatiable with CloudEvent spec v1.0.
pub type TopicEventRequest = dapr::proto::runtime::v1::TopicEventRequest; pub type TopicEventRequest = runtime::v1::TopicEventRequest;
/// TopicEventResponse is response from app on published message /// TopicEventResponse is response from app on published message
pub type TopicEventResponse = dapr::proto::runtime::v1::TopicEventResponse; pub type TopicEventResponse = runtime::v1::TopicEventResponse;
/// ListInputBindingsResponse is the message including the list of input bindings. /// ListInputBindingsResponse is the message including the list of input bindings.
pub type ListInputBindingsResponse = dapr::proto::runtime::v1::ListInputBindingsResponse; pub type ListInputBindingsResponse = runtime::v1::ListInputBindingsResponse;
/// BindingEventRequest represents input bindings event. /// BindingEventRequest represents input bindings event.
pub type BindingEventRequest = dapr::proto::runtime::v1::BindingEventRequest; pub type BindingEventRequest = runtime::v1::BindingEventRequest;
/// BindingEventResponse includes operations to save state or /// BindingEventResponse includes operations to save state or
/// send data to output bindings optionally. /// send data to output bindings optionally.
pub type BindingEventResponse = dapr::proto::runtime::v1::BindingEventResponse; pub type BindingEventResponse = runtime::v1::BindingEventResponse;
impl ListTopicSubscriptionsResponse { impl ListTopicSubscriptionsResponse {
/// Create `ListTopicSubscriptionsResponse` with a topic. /// Create `ListTopicSubscriptionsResponse` with a topic.

View File

@ -1,5 +1,4 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Debug;
use async_trait::async_trait; use async_trait::async_trait;
use futures::StreamExt; use futures::StreamExt;
@ -11,7 +10,7 @@ use tonic::codegen::tokio_stream;
use tonic::{transport::Channel as TonicChannel, Request}; use tonic::{transport::Channel as TonicChannel, Request};
use tonic::{Status, Streaming}; use tonic::{Status, Streaming};
use crate::dapr::dapr::proto::{common::v1 as common_v1, runtime::v1 as dapr_v1}; use crate::dapr::proto::{common::v1 as common_v1, runtime::v1 as dapr_v1};
use crate::error::Error; use crate::error::Error;
#[derive(Clone)] #[derive(Clone)]
@ -26,7 +25,27 @@ impl<T: DaprInterface> Client<T> {
pub async fn connect(addr: String) -> Result<Self, Error> { pub async fn connect(addr: String) -> Result<Self, Error> {
// Get the Dapr port to create a connection // Get the Dapr port to create a connection
let port: u16 = std::env::var("DAPR_GRPC_PORT")?.parse()?; let port: u16 = std::env::var("DAPR_GRPC_PORT")?.parse()?;
let address = format!("{}:{}", addr, port); let address = format!("{addr}:{port}");
Ok(Client(T::connect(address).await?))
}
/// Connect to the Dapr sidecar with a specific port.
///
/// # Arguments
///
/// * `addr` - Address of gRPC server to connect to.
/// * `port` - Port of the gRPC server to connect to.
pub async fn connect_with_port(addr: String, port: String) -> Result<Self, Error> {
// assert that port is between 1 and 65535
let port: u16 = match port.parse::<u16>() {
Ok(p) => p,
Err(_) => {
panic!("Port must be a number between 1 and 65535");
}
};
let address = format!("{addr}:{port}");
Ok(Client(T::connect(address).await?)) Ok(Client(T::connect(address).await?))
} }
@ -173,6 +192,7 @@ impl<T: DaprInterface> Client<T> {
/// ///
/// * `store_name` - The name of state store. /// * `store_name` - The name of state store.
/// * `key` - The key of the desired state. /// * `key` - The key of the desired state.
/// * `metadata` - Any metadata pairs to include in the request.
pub async fn get_state<S>( pub async fn get_state<S>(
&mut self, &mut self,
store_name: S, store_name: S,
@ -199,19 +219,54 @@ impl<T: DaprInterface> Client<T> {
/// Save an array of state objects. /// Save an array of state objects.
/// ///
/// This does not include any etag or metadata options.
///
/// # Arguments /// # Arguments
/// ///
/// * `store_name` - The name of state store. /// * `store_name` - The name of state store.
/// * `states` - The array of the state key values. /// * `key` - The key for the value
pub async fn save_state<I, K>(&mut self, store_name: K, states: I) -> Result<(), Error> /// * `value` - The value to be saved for the key
/// * `etag` - The etag identifier
/// * `metadata` - Any metadata pairs to include in the request.
/// * `options` - Any state option
pub async fn save_state<S>(
&mut self,
store_name: S,
key: S,
value: Vec<u8>,
etag: Option<Etag>,
metadata: Option<HashMap<String, String>>,
options: Option<StateOptions>,
) -> Result<(), Error>
where where
I: IntoIterator<Item = (K, Vec<u8>)>, S: Into<String>,
K: Into<String>, {
let states = vec![StateItem {
key: key.into(),
value,
etag,
metadata: metadata.unwrap_or_default(),
options,
}];
self.save_bulk_states(store_name, states).await
}
/// Save an array of state objects.
///
/// # Arguments
///
/// * `store_name` - The name of state store.
/// * `items` - The array of the state items.
pub async fn save_bulk_states<S, I>(&mut self, store_name: S, items: I) -> Result<(), Error>
where
S: Into<String>,
I: Into<Vec<StateItem>>,
{ {
self.0 self.0
.save_state(SaveStateRequest { .save_state(SaveStateRequest {
store_name: store_name.into(), store_name: store_name.into(),
states: states.into_iter().map(|pair| pair.into()).collect(), states: items.into(),
}) })
.await .await
} }
@ -427,7 +482,7 @@ impl<T: DaprInterface> Client<T> {
self.0.unsubscribe_configuration(request).await self.0.unsubscribe_configuration(request).await
} }
/// Encrypt binary data using Dapr. returns Vec<StreamPayload> to be used in decrypt method /// Encrypt binary data using Dapr. returns `Vec<StreamPayload>` to be used in decrypt method
/// ///
/// # Arguments /// # Arguments
/// ///
@ -468,11 +523,11 @@ impl<T: DaprInterface> Client<T> {
self.0.encrypt(requested_items).await self.0.encrypt(requested_items).await
} }
/// Decrypt binary data using Dapr. returns Vec<u8>. /// Decrypt binary data using Dapr. returns `Vec<u8>`.
/// ///
/// # Arguments /// # Arguments
/// ///
/// * `encrypted` - Encrypted data usually returned from encrypted, Vec<StreamPayload> /// * `encrypted` - Encrypted data usually returned from encrypted, `Vec<StreamPayload>`
/// * `options` - Decryption request options. /// * `options` - Decryption request options.
pub async fn decrypt( pub async fn decrypt(
&mut self, &mut self,
@ -534,6 +589,18 @@ impl<T: DaprInterface> Client<T> {
}; };
self.0.delete_job_alpha1(request).await self.0.delete_job_alpha1(request).await
} }
/// Converse with an LLM
///
/// # Arguments
///
/// * ConversationRequest - The request containing inputs to send to the LLM
pub async fn converse_alpha1(
&mut self,
request: ConversationRequest,
) -> Result<ConversationResponse, Error> {
self.0.converse_alpha1(request).await
}
} }
#[async_trait] #[async_trait]
@ -596,6 +663,11 @@ pub trait DaprInterface: Sized {
&mut self, &mut self,
request: DeleteJobRequest, request: DeleteJobRequest,
) -> Result<DeleteJobResponse, Error>; ) -> Result<DeleteJobResponse, Error>;
async fn converse_alpha1(
&mut self,
request: ConversationRequest,
) -> Result<ConversationResponse, Error>;
} }
#[async_trait] #[async_trait]
@ -604,6 +676,13 @@ impl DaprInterface for dapr_v1::dapr_client::DaprClient<TonicChannel> {
Ok(dapr_v1::dapr_client::DaprClient::connect(addr).await?) Ok(dapr_v1::dapr_client::DaprClient::connect(addr).await?)
} }
async fn publish_event(&mut self, request: PublishEventRequest) -> Result<(), Error> {
self.publish_event(Request::new(request))
.await?
.into_inner();
Ok(())
}
async fn invoke_service( async fn invoke_service(
&mut self, &mut self,
request: InvokeServiceRequest, request: InvokeServiceRequest,
@ -624,13 +703,6 @@ impl DaprInterface for dapr_v1::dapr_client::DaprClient<TonicChannel> {
.into_inner()) .into_inner())
} }
async fn publish_event(&mut self, request: PublishEventRequest) -> Result<(), Error> {
self.publish_event(Request::new(request))
.await?
.into_inner();
Ok(())
}
async fn get_secret(&mut self, request: GetSecretRequest) -> Result<GetSecretResponse, Error> { async fn get_secret(&mut self, request: GetSecretRequest) -> Result<GetSecretResponse, Error> {
Ok(self.get_secret(Request::new(request)).await?.into_inner()) Ok(self.get_secret(Request::new(request)).await?.into_inner())
} }
@ -649,6 +721,11 @@ impl DaprInterface for dapr_v1::dapr_client::DaprClient<TonicChannel> {
Ok(self.get_state(Request::new(request)).await?.into_inner()) Ok(self.get_state(Request::new(request)).await?.into_inner())
} }
async fn save_state(&mut self, request: SaveStateRequest) -> Result<(), Error> {
self.save_state(Request::new(request)).await?.into_inner();
Ok(())
}
async fn query_state_alpha1( async fn query_state_alpha1(
&mut self, &mut self,
request: QueryStateRequest, request: QueryStateRequest,
@ -659,11 +736,6 @@ impl DaprInterface for dapr_v1::dapr_client::DaprClient<TonicChannel> {
.into_inner()) .into_inner())
} }
async fn save_state(&mut self, request: SaveStateRequest) -> Result<(), Error> {
self.save_state(Request::new(request)).await?.into_inner();
Ok(())
}
async fn delete_state(&mut self, request: DeleteStateRequest) -> Result<(), Error> { async fn delete_state(&mut self, request: DeleteStateRequest) -> Result<(), Error> {
self.delete_state(Request::new(request)).await?.into_inner(); self.delete_state(Request::new(request)).await?.into_inner();
Ok(()) Ok(())
@ -722,7 +794,7 @@ impl DaprInterface for dapr_v1::dapr_client::DaprClient<TonicChannel> {
.into_inner()) .into_inner())
} }
/// Encrypt binary data using Dapr. returns Vec<StreamPayload> to be used in decrypt method /// Encrypt binary data using Dapr. returns `Vec<StreamPayload>` to be used in decrypt method
/// ///
/// # Arguments /// # Arguments
/// ///
@ -746,11 +818,11 @@ impl DaprInterface for dapr_v1::dapr_client::DaprClient<TonicChannel> {
Ok(return_data) Ok(return_data)
} }
/// Decrypt binary data using Dapr. returns Vec<u8>. /// Decrypt binary data using Dapr. returns `Vec<u8>`.
/// ///
/// # Arguments /// # Arguments
/// ///
/// * `encrypted` - Encrypted data usually returned from encrypted, Vec<StreamPayload> /// * `encrypted` - Encrypted data usually returned from encrypted, `Vec<StreamPayload>`
/// * `options` - Decryption request options. /// * `options` - Decryption request options.
async fn decrypt(&mut self, request: Vec<DecryptRequest>) -> Result<Vec<u8>, Status> { async fn decrypt(&mut self, request: Vec<DecryptRequest>) -> Result<Vec<u8>, Status> {
let request = Request::new(tokio_stream::iter(request)); let request = Request::new(tokio_stream::iter(request));
@ -790,6 +862,16 @@ impl DaprInterface for dapr_v1::dapr_client::DaprClient<TonicChannel> {
.await? .await?
.into_inner()) .into_inner())
} }
async fn converse_alpha1(
&mut self,
request: ConversationRequest,
) -> Result<ConversationResponse, Error> {
Ok(self
.converse_alpha1(Request::new(request))
.await?
.into_inner())
}
} }
/// A request from invoking a service /// A request from invoking a service
@ -816,6 +898,15 @@ pub type GetStateResponse = dapr_v1::GetStateResponse;
/// A request for saving state /// A request for saving state
pub type SaveStateRequest = dapr_v1::SaveStateRequest; pub type SaveStateRequest = dapr_v1::SaveStateRequest;
/// A state item
pub type StateItem = common_v1::StateItem;
/// State options
pub type StateOptions = common_v1::StateOptions;
/// Etag identifier
pub type Etag = common_v1::Etag;
/// A request for querying state /// A request for querying state
pub type QueryStateRequest = dapr_v1::QueryStateRequest; pub type QueryStateRequest = dapr_v1::QueryStateRequest;
@ -876,39 +967,51 @@ pub type UnsubscribeConfigurationResponse = dapr_v1::UnsubscribeConfigurationRes
pub type TonicClient = dapr_v1::dapr_client::DaprClient<TonicChannel>; pub type TonicClient = dapr_v1::dapr_client::DaprClient<TonicChannel>;
/// Encryption gRPC request /// Encryption gRPC request
pub type EncryptRequest = crate::dapr::dapr::proto::runtime::v1::EncryptRequest; pub type EncryptRequest = crate::dapr::proto::runtime::v1::EncryptRequest;
/// Decrypt gRPC request /// Decrypt gRPC request
pub type DecryptRequest = crate::dapr::dapr::proto::runtime::v1::DecryptRequest; pub type DecryptRequest = crate::dapr::proto::runtime::v1::DecryptRequest;
/// Encryption request options /// Encryption request options
pub type EncryptRequestOptions = crate::dapr::dapr::proto::runtime::v1::EncryptRequestOptions; pub type EncryptRequestOptions = crate::dapr::proto::runtime::v1::EncryptRequestOptions;
/// Decryption request options /// Decryption request options
pub type DecryptRequestOptions = crate::dapr::dapr::proto::runtime::v1::DecryptRequestOptions; pub type DecryptRequestOptions = crate::dapr::proto::runtime::v1::DecryptRequestOptions;
/// The basic job structure /// The basic job structure
pub type Job = crate::dapr::dapr::proto::runtime::v1::Job; pub type Job = crate::dapr::proto::runtime::v1::Job;
/// A request to schedule a job /// A request to schedule a job
pub type ScheduleJobRequest = crate::dapr::dapr::proto::runtime::v1::ScheduleJobRequest; pub type ScheduleJobRequest = crate::dapr::proto::runtime::v1::ScheduleJobRequest;
/// A response from a schedule job request /// A response from a schedule job request
pub type ScheduleJobResponse = crate::dapr::dapr::proto::runtime::v1::ScheduleJobResponse; pub type ScheduleJobResponse = crate::dapr::proto::runtime::v1::ScheduleJobResponse;
/// A request to get a job /// A request to get a job
pub type GetJobRequest = crate::dapr::dapr::proto::runtime::v1::GetJobRequest; pub type GetJobRequest = crate::dapr::proto::runtime::v1::GetJobRequest;
/// A response from a get job request /// A response from a get job request
pub type GetJobResponse = crate::dapr::dapr::proto::runtime::v1::GetJobResponse; pub type GetJobResponse = crate::dapr::proto::runtime::v1::GetJobResponse;
/// A request to delete a job /// A request to delete a job
pub type DeleteJobRequest = crate::dapr::dapr::proto::runtime::v1::DeleteJobRequest; pub type DeleteJobRequest = crate::dapr::proto::runtime::v1::DeleteJobRequest;
/// A response from a delete job request /// A response from a delete job request
pub type DeleteJobResponse = crate::dapr::dapr::proto::runtime::v1::DeleteJobResponse; pub type DeleteJobResponse = crate::dapr::proto::runtime::v1::DeleteJobResponse;
type StreamPayload = crate::dapr::dapr::proto::common::v1::StreamPayload; /// A request to conversate with an LLM
pub type ConversationRequest = crate::dapr::proto::runtime::v1::ConversationRequest;
/// A response from conversating with an LLM
pub type ConversationResponse = crate::dapr::proto::runtime::v1::ConversationResponse;
/// A result from an interacting with a LLM
pub type ConversationResult = crate::dapr::proto::runtime::v1::ConversationResult;
/// An input to the conversation
pub type ConversationInput = crate::dapr::proto::runtime::v1::ConversationInput;
type StreamPayload = crate::dapr::proto::common::v1::StreamPayload;
impl<K> From<(K, Vec<u8>)> for common_v1::StateItem impl<K> From<(K, Vec<u8>)> for common_v1::StateItem
where where
K: Into<String>, K: Into<String>,
@ -930,7 +1033,6 @@ impl<T: AsyncRead> ReaderStream<T> {
} }
} }
#[derive(Debug)]
pub struct JobBuilder { pub struct JobBuilder {
schedule: Option<String>, schedule: Option<String>,
data: Option<Any>, data: Option<Any>,
@ -989,3 +1091,62 @@ impl JobBuilder {
} }
} }
} }
pub struct ConversationInputBuilder {
content: String,
role: Option<String>,
scrub_pii: Option<bool>,
}
impl ConversationInputBuilder {
pub fn new(message: &str) -> Self {
ConversationInputBuilder {
content: message.to_string(),
role: None,
scrub_pii: None,
}
}
pub fn build(self) -> ConversationInput {
ConversationInput {
content: self.content,
role: self.role,
scrub_pii: self.scrub_pii,
}
}
}
pub struct ConversationRequestBuilder {
name: String,
context_id: Option<String>,
inputs: Vec<ConversationInput>,
parameters: HashMap<String, Any>,
metadata: HashMap<String, String>,
scrub_pii: Option<bool>,
temperature: Option<f64>,
}
impl ConversationRequestBuilder {
pub fn new(name: &str, inputs: Vec<ConversationInput>) -> Self {
ConversationRequestBuilder {
name: name.to_string(),
context_id: None,
inputs,
parameters: Default::default(),
metadata: Default::default(),
scrub_pii: None,
temperature: None,
}
}
pub fn build(self) -> ConversationRequest {
ConversationRequest {
name: self.name,
context_id: self.context_id,
inputs: self.inputs,
parameters: self.parameters,
metadata: self.metadata,
scrub_pii: self.scrub_pii,
temperature: self.temperature,
}
}
}

3
dapr/src/dapr/README.md Normal file
View File

@ -0,0 +1,3 @@
# dapr
These are compiled by running the proto-gen crate

View File

@ -0,0 +1,272 @@
// This file is @generated by prost-build.
/// HTTPExtension includes HTTP verb and querystring
/// when Dapr runtime delivers HTTP content.
///
/// For example, when callers calls http invoke api
/// `POST <http://localhost:3500/v1.0/invoke/<app_id>/method/<method>?query1=value1&query2=value2`>
///
/// Dapr runtime will parse POST as a verb and extract querystring to quersytring map.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct HttpExtension {
/// Required. HTTP verb.
#[prost(enumeration = "http_extension::Verb", tag = "1")]
pub verb: i32,
/// Optional. querystring represents an encoded HTTP url query string in the following format: name=value&name2=value2
#[prost(string, tag = "2")]
pub querystring: ::prost::alloc::string::String,
}
/// Nested message and enum types in `HTTPExtension`.
pub mod http_extension {
/// Type of HTTP 1.1 Methods
/// RFC 7231: <https://tools.ietf.org/html/rfc7231#page-24>
/// RFC 5789: <https://datatracker.ietf.org/doc/html/rfc5789>
#[derive(
Clone,
Copy,
Debug,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
::prost::Enumeration
)]
#[repr(i32)]
pub enum Verb {
None = 0,
Get = 1,
Head = 2,
Post = 3,
Put = 4,
Delete = 5,
Connect = 6,
Options = 7,
Trace = 8,
Patch = 9,
}
impl Verb {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
Self::None => "NONE",
Self::Get => "GET",
Self::Head => "HEAD",
Self::Post => "POST",
Self::Put => "PUT",
Self::Delete => "DELETE",
Self::Connect => "CONNECT",
Self::Options => "OPTIONS",
Self::Trace => "TRACE",
Self::Patch => "PATCH",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"NONE" => Some(Self::None),
"GET" => Some(Self::Get),
"HEAD" => Some(Self::Head),
"POST" => Some(Self::Post),
"PUT" => Some(Self::Put),
"DELETE" => Some(Self::Delete),
"CONNECT" => Some(Self::Connect),
"OPTIONS" => Some(Self::Options),
"TRACE" => Some(Self::Trace),
"PATCH" => Some(Self::Patch),
_ => None,
}
}
}
}
/// InvokeRequest is the message to invoke a method with the data.
/// This message is used in InvokeService of Dapr gRPC Service and OnInvoke
/// of AppCallback gRPC service.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct InvokeRequest {
/// Required. method is a method name which will be invoked by caller.
#[prost(string, tag = "1")]
pub method: ::prost::alloc::string::String,
/// Required in unary RPCs. Bytes value or Protobuf message which caller sent.
/// Dapr treats Any.value as bytes type if Any.type_url is unset.
#[prost(message, optional, tag = "2")]
pub data: ::core::option::Option<::prost_types::Any>,
/// The type of data content.
///
/// This field is required if data delivers http request body
/// Otherwise, this is optional.
#[prost(string, tag = "3")]
pub content_type: ::prost::alloc::string::String,
/// HTTP specific fields if request conveys http-compatible request.
///
/// This field is required for http-compatible request. Otherwise,
/// this field is optional.
#[prost(message, optional, tag = "4")]
pub http_extension: ::core::option::Option<HttpExtension>,
}
/// InvokeResponse is the response message including data and its content type
/// from app callback.
/// This message is used in InvokeService of Dapr gRPC Service and OnInvoke
/// of AppCallback gRPC service.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct InvokeResponse {
/// Required in unary RPCs. The content body of InvokeService response.
#[prost(message, optional, tag = "1")]
pub data: ::core::option::Option<::prost_types::Any>,
/// Required. The type of data content.
#[prost(string, tag = "2")]
pub content_type: ::prost::alloc::string::String,
}
/// Chunk of data sent in a streaming request or response.
/// This is used in requests including InternalInvokeRequestStream.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct StreamPayload {
/// Data sent in the chunk.
/// The amount of data included in each chunk is up to the discretion of the sender, and can be empty.
/// Additionally, the amount of data doesn't need to be fixed and subsequent messages can send more, or less, data.
/// Receivers must not make assumptions about the number of bytes they'll receive in each chunk.
#[prost(bytes = "vec", tag = "1")]
pub data: ::prost::alloc::vec::Vec<u8>,
/// Sequence number. This is a counter that starts from 0 and increments by 1 on each chunk sent.
#[prost(uint64, tag = "2")]
pub seq: u64,
}
/// StateItem represents state key, value, and additional options to save state.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct StateItem {
/// Required. The state key
#[prost(string, tag = "1")]
pub key: ::prost::alloc::string::String,
/// Required. The state data for key
#[prost(bytes = "vec", tag = "2")]
pub value: ::prost::alloc::vec::Vec<u8>,
/// The entity tag which represents the specific version of data.
/// The exact ETag format is defined by the corresponding data store.
#[prost(message, optional, tag = "3")]
pub etag: ::core::option::Option<Etag>,
/// The metadata which will be passed to state store component.
#[prost(map = "string, string", tag = "4")]
pub metadata: ::std::collections::HashMap<
::prost::alloc::string::String,
::prost::alloc::string::String,
>,
/// Options for concurrency and consistency to save the state.
#[prost(message, optional, tag = "5")]
pub options: ::core::option::Option<StateOptions>,
}
/// Etag represents a state item version
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Etag {
/// value sets the etag value
#[prost(string, tag = "1")]
pub value: ::prost::alloc::string::String,
}
/// StateOptions configures concurrency and consistency for state operations
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct StateOptions {
#[prost(enumeration = "state_options::StateConcurrency", tag = "1")]
pub concurrency: i32,
#[prost(enumeration = "state_options::StateConsistency", tag = "2")]
pub consistency: i32,
}
/// Nested message and enum types in `StateOptions`.
pub mod state_options {
/// Enum describing the supported concurrency for state.
#[derive(
Clone,
Copy,
Debug,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
::prost::Enumeration
)]
#[repr(i32)]
pub enum StateConcurrency {
ConcurrencyUnspecified = 0,
ConcurrencyFirstWrite = 1,
ConcurrencyLastWrite = 2,
}
impl StateConcurrency {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
Self::ConcurrencyUnspecified => "CONCURRENCY_UNSPECIFIED",
Self::ConcurrencyFirstWrite => "CONCURRENCY_FIRST_WRITE",
Self::ConcurrencyLastWrite => "CONCURRENCY_LAST_WRITE",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"CONCURRENCY_UNSPECIFIED" => Some(Self::ConcurrencyUnspecified),
"CONCURRENCY_FIRST_WRITE" => Some(Self::ConcurrencyFirstWrite),
"CONCURRENCY_LAST_WRITE" => Some(Self::ConcurrencyLastWrite),
_ => None,
}
}
}
/// Enum describing the supported consistency for state.
#[derive(
Clone,
Copy,
Debug,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
::prost::Enumeration
)]
#[repr(i32)]
pub enum StateConsistency {
ConsistencyUnspecified = 0,
ConsistencyEventual = 1,
ConsistencyStrong = 2,
}
impl StateConsistency {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
Self::ConsistencyUnspecified => "CONSISTENCY_UNSPECIFIED",
Self::ConsistencyEventual => "CONSISTENCY_EVENTUAL",
Self::ConsistencyStrong => "CONSISTENCY_STRONG",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"CONSISTENCY_UNSPECIFIED" => Some(Self::ConsistencyUnspecified),
"CONSISTENCY_EVENTUAL" => Some(Self::ConsistencyEventual),
"CONSISTENCY_STRONG" => Some(Self::ConsistencyStrong),
_ => None,
}
}
}
}
/// ConfigurationItem represents all the configuration with its name(key).
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ConfigurationItem {
/// Required. The value of configuration item.
#[prost(string, tag = "1")]
pub value: ::prost::alloc::string::String,
/// Version is response only and cannot be fetched. Store is not expected to keep all versions available
#[prost(string, tag = "2")]
pub version: ::prost::alloc::string::String,
/// the metadata which will be passed to/from configuration store component.
#[prost(map = "string, string", tag = "3")]
pub metadata: ::std::collections::HashMap<
::prost::alloc::string::String,
::prost::alloc::string::String,
>,
}

File diff suppressed because it is too large Load Diff

BIN
dapr/src/dapr/types.bin Normal file

Binary file not shown.

View File

@ -13,7 +13,7 @@ pub enum Error {
impl Display for Error { impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self) write!(f, "{self:?}")
} }
} }
@ -50,6 +50,6 @@ pub struct GrpcError {
impl Display for GrpcError { impl Display for GrpcError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self) write!(f, "{self:?}")
} }
} }

View File

@ -1,8 +1,5 @@
#![doc = include_str!("../README.md")] #![doc = include_str!("../README.md")]
extern crate dapr_macros;
pub use dapr_macros::actor;
pub use serde; pub use serde;
pub use serde_json; pub use serde_json;
@ -12,8 +9,23 @@ pub use client::Client;
pub mod appcallback; pub mod appcallback;
/// Module containing the 'Client' implementation. /// Module containing the 'Client' implementation.
pub mod client; pub mod client;
/// Module importing the Dapr runtime implementation. /// Module importing the Dapr runtime implementation.
pub mod dapr; pub mod dapr {
#![allow(clippy::large_enum_variant)]
pub mod proto {
pub mod common {
pub mod v1 {
include!("dapr/dapr.proto.common.v1.rs");
}
}
pub mod runtime {
pub mod v1 {
include!("dapr/dapr.proto.runtime.v1.rs");
}
}
}
}
/// Module defining the error implementations. /// Module defining the error implementations.
pub mod error; pub mod error;
/// Module containing the 'Server' implementation. /// Module containing the 'Server' implementation.

View File

@ -1,5 +1,5 @@
use crate::client::TonicClient; use crate::client::TonicClient;
use crate::dapr::dapr::proto::runtime::v1 as dapr_v1; use crate::dapr::proto::runtime::v1 as dapr_v1;
use crate::error::Error as DaprError; use crate::error::Error as DaprError;
use prost_types::Any; use prost_types::Any;
use std::collections::HashMap; use std::collections::HashMap;

View File

@ -37,7 +37,7 @@ impl Display for ActorError {
ActorError::CorruptedState => write!(f, "Actor state corrupted"), ActorError::CorruptedState => write!(f, "Actor state corrupted"),
ActorError::MethodNotFound => write!(f, "Method not found"), ActorError::MethodNotFound => write!(f, "Method not found"),
ActorError::ActorNotFound => write!(f, "Actor not found"), ActorError::ActorNotFound => write!(f, "Actor not found"),
ActorError::MethodError(e) => write!(f, "Method error: {}", e), ActorError::MethodError(e) => write!(f, "Method error: {e}"),
ActorError::SerializationError() => write!(f, "Serialization error"), ActorError::SerializationError() => write!(f, "Serialization error"),
} }
} }

View File

@ -174,7 +174,7 @@ impl ActorTypeRegistration {
T: 'static, T: 'static,
{ {
let actor_type = self.name.clone(); let actor_type = self.name.clone();
let method_path = format!("/actors/{}/:actor_id/method/{}", actor_type, method_name); let method_path = format!("/actors/{actor_type}/:actor_id/method/{method_name}");
let reg_func = move |router: Router, runtime: Arc<ActorRuntime>| { let reg_func = move |router: Router, runtime: Arc<ActorRuntime>| {
router.route( router.route(
@ -224,7 +224,7 @@ impl ActorRuntime {
let name = registration.name.clone(); let name = registration.name.clone();
let mut g = self.registered_actors_types.write().await; let mut g = self.registered_actors_types.write().await;
g.insert(name.clone(), registration); g.insert(name.clone(), registration);
log::info!("registered actor {}", name); log::info!("registered actor {name}");
} }
pub async fn configure_method_routes( pub async fn configure_method_routes(

View File

@ -1,3 +1,4 @@
#[cfg(test)]
use std::{collections::HashMap, sync::Arc}; use std::{collections::HashMap, sync::Arc};
use async_trait::async_trait; use async_trait::async_trait;
@ -96,7 +97,7 @@ async fn test_actor_invoke() {
let server = TestServer::new(app.into_make_service()).unwrap(); let server = TestServer::new(app.into_make_service()).unwrap();
let invoke_resp = server let invoke_resp = server
.put(&format!("/actors/MyActor/{}/method/do_stuff", actor_id)) .put(&format!("/actors/MyActor/{actor_id}/method/do_stuff"))
.json(&json!({ "name": "foo" })) .json(&json!({ "name": "foo" }))
.await; .await;
invoke_resp.assert_status_ok(); invoke_resp.assert_status_ok();
@ -117,7 +118,7 @@ async fn test_actor_invoke() {
); );
let invoke_resp2 = server let invoke_resp2 = server
.put(&format!("/actors/MyActor/{}/method/do_stuff", actor_id)) .put(&format!("/actors/MyActor/{actor_id}/method/do_stuff"))
.json(&json!({ "name": "foo" })) .json(&json!({ "name": "foo" }))
.await; .await;
invoke_resp2.assert_status_ok(); invoke_resp2.assert_status_ok();
@ -168,19 +169,15 @@ async fn test_actor_deactivate() {
let actor_id = Uuid::new_v4().to_string(); let actor_id = Uuid::new_v4().to_string();
let invoke_resp = server let invoke_resp = server
.put(&format!("/actors/MyActor/{}/method/do_stuff", actor_id)) .put(&format!("/actors/MyActor/{actor_id}/method/do_stuff"))
.json(&json!({ "name": "foo" })) .json(&json!({ "name": "foo" }))
.await; .await;
invoke_resp.assert_status_ok(); invoke_resp.assert_status_ok();
let deactivate_resp1 = server let deactivate_resp1 = server.delete(&format!("/actors/MyActor/{actor_id}")).await;
.delete(&format!("/actors/MyActor/{}", actor_id))
.await;
deactivate_resp1.assert_status_ok(); deactivate_resp1.assert_status_ok();
let deactivate_resp2 = server let deactivate_resp2 = server.delete(&format!("/actors/MyActor/{actor_id}")).await;
.delete(&format!("/actors/MyActor/{}", actor_id))
.await;
deactivate_resp2.assert_status_not_found(); deactivate_resp2.assert_status_not_found();
assert_eq!( assert_eq!(

View File

@ -2,8 +2,8 @@ use std::collections::HashMap;
use tonic::{Code, Request, Response, Status}; use tonic::{Code, Request, Response, Status};
use crate::dapr::dapr::proto::runtime; use crate::dapr::proto::runtime;
use crate::dapr::dapr::proto::runtime::v1::app_callback_alpha_server::AppCallbackAlpha; use crate::dapr::proto::runtime::v1::app_callback_alpha_server::AppCallbackAlpha;
pub struct AppCallbackServiceAlpha { pub struct AppCallbackServiceAlpha {
pub job_handlers: HashMap<String, Box<dyn JobHandlerMethod + Send + Sync + 'static>>, pub job_handlers: HashMap<String, Box<dyn JobHandlerMethod + Send + Sync + 'static>>,

View File

@ -1,5 +1,5 @@
use axum::{ use axum::{
extract::{Path, State}, extract::{OriginalUri, Path, State},
http::StatusCode, http::StatusCode,
response::IntoResponse, response::IntoResponse,
routing::{delete, get, put}, routing::{delete, get, put},
@ -84,6 +84,12 @@ pub struct DaprHttpServer {
impl DaprHttpServer { impl DaprHttpServer {
/// Creates a new instance of the Dapr HTTP server with default options. /// Creates a new instance of the Dapr HTTP server with default options.
///
/// # Panics
///
/// This function panics if the Dapr Sidecar cannot be reached!
/// For a non-panicking version that allows you to handle any errors yourself, see:
/// [DaprHttpServer::try_new_with_dapr_port]
pub async fn new() -> Self { pub async fn new() -> Self {
let dapr_port: u16 = std::env::var("DAPR_GRPC_PORT") let dapr_port: u16 = std::env::var("DAPR_GRPC_PORT")
.unwrap_or("3501".into()) .unwrap_or("3501".into())
@ -92,19 +98,38 @@ impl DaprHttpServer {
Self::with_dapr_port(dapr_port).await Self::with_dapr_port(dapr_port).await
} }
/// Creates a new instance of the Dapr HTTP server that connects to the Dapr sidecar on the
/// given dapr_port.
///
/// # Panics
///
/// This function panics if the Dapr Sidecar cannot be reached!
/// For a non-panicking version that allows you to handle any errors yourself, see:
/// [DaprHttpServer::try_new_with_dapr_port]
pub async fn with_dapr_port(dapr_port: u16) -> Self { pub async fn with_dapr_port(dapr_port: u16) -> Self {
let dapr_addr = format!("https://127.0.0.1:{}", dapr_port); match Self::try_new_with_dapr_port(dapr_port).await {
let cc = match TonicClient::connect(dapr_addr).await {
Ok(c) => c, Ok(c) => c,
Err(err) => panic!("failed to connect to dapr: {}", err), Err(err) => panic!("failed to connect to dapr: {err}"),
}; }
}
/// Creates a new instance of the Dapr HTTP server that connects to the Dapr sidecar on the
/// given dapr_port.
///
/// In contrast to the other functions that create a DaprHttpServer, this function does
/// not panic, but instead returns a Result.
pub async fn try_new_with_dapr_port(
dapr_port: u16,
) -> Result<Self, Box<dyn std::error::Error>> {
let dapr_addr = format!("https://127.0.0.1:{dapr_port}");
let cc = TonicClient::connect(dapr_addr).await?;
let rt = ActorRuntime::new(cc); let rt = ActorRuntime::new(cc);
DaprHttpServer { Ok(DaprHttpServer {
actor_runtime: Arc::new(rt), actor_runtime: Arc::new(rt),
shutdown_signal: None, shutdown_signal: None,
} })
} }
pub fn with_graceful_shutdown<F>(self, signal: F) -> Self pub fn with_graceful_shutdown<F>(self, signal: F) -> Self
@ -138,7 +163,7 @@ impl DaprHttpServer {
.unwrap_or(8080); .unwrap_or(8080);
let address = format!("127.0.0.1:{}", port.unwrap_or(default_port)); let address = format!("127.0.0.1:{}", port.unwrap_or(default_port));
let listener = TcpListener::bind(address).await.unwrap(); let listener = TcpListener::bind(address).await?;
let server = axum::serve(listener, app.into_make_service()); let server = axum::serve(listener, app.into_make_service());
@ -182,7 +207,8 @@ impl DaprHttpServer {
.route( .route(
"/actors/:actor_type/:actor_id/method/timer/:timer_name", "/actors/:actor_type/:actor_id/method/timer/:timer_name",
put(invoke_timer).with_state(rt.clone()), put(invoke_timer).with_state(rt.clone()),
); )
.fallback(fallback_handler);
self.actor_runtime self.actor_runtime
.configure_method_routes(app, rt.clone()) .configure_method_routes(app, rt.clone())
@ -190,6 +216,14 @@ impl DaprHttpServer {
} }
} }
async fn fallback_handler(OriginalUri(uri): OriginalUri) -> impl IntoResponse {
log::warn!("Returning 404 for request: {uri}");
(
StatusCode::NOT_FOUND,
format!("The URI '{uri}' could not be found!"),
)
}
async fn health_check() -> impl IntoResponse { async fn health_check() -> impl IntoResponse {
log::debug!("recieved health check request"); log::debug!("recieved health check request");
StatusCode::OK StatusCode::OK
@ -210,11 +244,11 @@ async fn deactivate_actor(
match runtime.deactivate_actor(&actor_type, &actor_id).await { match runtime.deactivate_actor(&actor_type, &actor_id).await {
Ok(_) => StatusCode::OK, Ok(_) => StatusCode::OK,
Err(err) => { Err(err) => {
log::error!("invoke_actor: {:?}", err); log::error!("invoke_actor: {err:?}");
match err { match err {
super::actor::ActorError::ActorNotFound => StatusCode::NOT_FOUND, super::actor::ActorError::ActorNotFound => StatusCode::NOT_FOUND,
_ => { _ => {
log::error!("deactivate_actor: {:?}", err); log::error!("deactivate_actor: {err:?}");
StatusCode::INTERNAL_SERVER_ERROR StatusCode::INTERNAL_SERVER_ERROR
} }
} }
@ -227,13 +261,7 @@ async fn invoke_reminder(
Path((actor_type, actor_id, reminder_name)): Path<(String, String, String)>, Path((actor_type, actor_id, reminder_name)): Path<(String, String, String)>,
Json(payload): Json<ReminderPayload>, Json(payload): Json<ReminderPayload>,
) -> impl IntoResponse { ) -> impl IntoResponse {
log::debug!( log::debug!("invoke_reminder: {actor_type} {actor_id} {reminder_name} {payload:?}");
"invoke_reminder: {} {} {} {:?}",
actor_type,
actor_id,
reminder_name,
payload
);
match runtime match runtime
.invoke_reminder( .invoke_reminder(
@ -246,11 +274,11 @@ async fn invoke_reminder(
{ {
Ok(_output) => StatusCode::OK, Ok(_output) => StatusCode::OK,
Err(err) => { Err(err) => {
log::error!("invoke_actor: {:?}", err); log::error!("invoke_actor: {err:?}");
match err { match err {
super::actor::ActorError::ActorNotFound => StatusCode::NOT_FOUND, super::actor::ActorError::ActorNotFound => StatusCode::NOT_FOUND,
_ => { _ => {
log::error!("invoke_reminder: {:?}", err); log::error!("invoke_reminder: {err:?}");
StatusCode::INTERNAL_SERVER_ERROR StatusCode::INTERNAL_SERVER_ERROR
} }
} }
@ -263,13 +291,7 @@ async fn invoke_timer(
Path((actor_type, actor_id, timer_name)): Path<(String, String, String)>, Path((actor_type, actor_id, timer_name)): Path<(String, String, String)>,
Json(payload): Json<TimerPayload>, Json(payload): Json<TimerPayload>,
) -> impl IntoResponse { ) -> impl IntoResponse {
log::debug!( log::debug!("invoke_timer: {actor_type} {actor_id} {timer_name}, {payload:?}");
"invoke_timer: {} {} {}, {:?}",
actor_type,
actor_id,
timer_name,
payload
);
match runtime match runtime
.invoke_timer( .invoke_timer(
@ -282,11 +304,11 @@ async fn invoke_timer(
{ {
Ok(_output) => StatusCode::OK, Ok(_output) => StatusCode::OK,
Err(err) => { Err(err) => {
log::error!("invoke_actor: {:?}", err); log::error!("invoke_actor: {err:?}");
match err { match err {
super::actor::ActorError::ActorNotFound => StatusCode::NOT_FOUND, super::actor::ActorError::ActorNotFound => StatusCode::NOT_FOUND,
_ => { _ => {
log::error!("invoke_timer: {:?}", err); log::error!("invoke_timer: {err:?}");
StatusCode::INTERNAL_SERVER_ERROR StatusCode::INTERNAL_SERVER_ERROR
} }
} }

View File

@ -28,14 +28,14 @@ where
let bytes = match axum::body::Bytes::from_request(req, state).await { let bytes = match axum::body::Bytes::from_request(req, state).await {
Ok(bytes) => bytes, Ok(bytes) => bytes,
Err(e) => { Err(e) => {
log::error!("Error getting bytes: {}", e); log::error!("Error getting bytes: {e}");
return Err(JsonRejection::JsonError(e.to_string())); return Err(JsonRejection::JsonError(e.to_string()));
} }
}; };
let value = match serde_json::from_slice::<T>(&bytes) { let value = match serde_json::from_slice::<T>(&bytes) {
Ok(value) => value, Ok(value) => value,
Err(e) => { Err(e) => {
log::error!("Error deserializing JSON: {}", e); log::error!("Error deserializing JSON: {e}");
return Err(JsonRejection::JsonError(e.to_string())); return Err(JsonRejection::JsonError(e.to_string()));
} }
}; };

View File

@ -8,13 +8,14 @@ All Dapr documentation is hosted at [docs.dapr.io](https://docs.dapr.io), includ
### Rust SDK docs source ### Rust SDK docs source
Although the docs site code and content is in the [docs repo](https://github.com/dapr/docs), the Go SDK content and images are within the `content` and `static` directories, respectively. Although the docs site code and content is in the [docs repo](https://github.com/dapr/docs), the Rust SDK content and images are within the `content` and `static` directories, respectively.
This allows separation of roles and expertise between maintainers, and makes it easy to find the docs files you are looking for. This allows separation of roles and expertise between maintainers, and makes it easy to find the docs files you are looking for.
## Writing Rust SDK docs ## Writing Rust SDK docs
To get up and running to write Go SDK docs, visit the [docs repo](https://github.com/dapr/docs) to initialize your environment. It will clone both the docs repo and this repo, so you can make changes and see it rendered within the site instantly, as well as commit and PR into this repo. To get up and running to write Rust SDK docs, visit the [docs repo](https://github.com/dapr/docs) to initialize your
environment. It will clone both the docs repo and this repo, so you can make changes and see it rendered within the site instantly, as well as commit and PR into this repo.
Make sure to read the [docs contributing guide](https://docs.dapr.io/contributing/contributing-docs/) for information on style/semantics/etc. Make sure to read the [docs contributing guide](https://docs.dapr.io/contributing/contributing-docs/) for information on style/semantics/etc.

View File

@ -12,7 +12,7 @@ When contributing to the [Rust SDK](https://github.com/dapr/rust-sdk) the follow
The `examples` directory contains code samples for users to run to try out specific functionality of the various Rust SDK packages and extensions. It also hosts component examples used for validation. When writing new and updated samples keep in mind: The `examples` directory contains code samples for users to run to try out specific functionality of the various Rust SDK packages and extensions. It also hosts component examples used for validation. When writing new and updated samples keep in mind:
- All examples should be runnable on Windows, Linux, and MacOS. While Rust code is consistent among operating systems aside from minor OS-feature gating, any pre/post example commands should provide options through [codetabs]({{< ref "contributing-docs.md#tabbed-content" >}}) - All examples should be runnable on Windows, Linux, and MacOS. While Rust code is consistent among operating systems aside from minor OS-feature gating, any pre/post example commands should provide options through [tabpane]({{% ref "contributing-docs.md#tabbed-content" %}})
- Contain steps to download/install any required pre-requisites. Someone coming in with a fresh OS install should be able to start on the example and complete it without an error. Links to external download pages are fine. - Contain steps to download/install any required pre-requisites. Someone coming in with a fresh OS install should be able to start on the example and complete it without an error. Links to external download pages are fine.
- Examples should be pass validation and include mechanical markdown steps and be added to the validation workflow [TBA](#) - Examples should be pass validation and include mechanical markdown steps and be added to the validation workflow [TBA](#)
@ -20,7 +20,7 @@ The `examples` directory contains code samples for users to run to try out speci
The `daprdocs` directory contains the markdown files that are rendered into the [Dapr Docs](https://docs.dapr.io) website. When the documentation website is built this repo is cloned and configured so that its contents are rendered with the docs content. When writing docs keep in mind: The `daprdocs` directory contains the markdown files that are rendered into the [Dapr Docs](https://docs.dapr.io) website. When the documentation website is built this repo is cloned and configured so that its contents are rendered with the docs content. When writing docs keep in mind:
- All rules in the [docs guide]({{< ref contributing-docs.md >}}) should be followed in addition to these. - All rules in the [docs guide]({{% ref contributing-docs.md %}}) should be followed in addition to these.
- All files and directories should be prefixed with `rust-` to ensure all file/directory names are globally unique across all Dapr documentation. - All files and directories should be prefixed with `rust-` to ensure all file/directory names are globally unique across all Dapr documentation.
## Update Protobufs ## Update Protobufs

View File

@ -22,6 +22,6 @@ A client library to help build Dapr applications using Rust. This client is targ
{{< card title="**Client**">}} {{< card title="**Client**">}}
Use the Rust Client SDK for invoking public Dapr APIs Use the Rust Client SDK for invoking public Dapr APIs
[**Learn more about the Rust Client SDK**]({{< ref rust-client >}}) [**Learn more about the Rust Client SDK**]({{% ref rust-client %}})
{{< /card >}} {{< /card >}}
{{< /cardpane >}} {{< /cardpane >}}

View File

@ -7,19 +7,20 @@ description: How to get up and running with the Dapr Rust SDK
no_list: true no_list: true
--- ---
The Dapr client package allows you to interact with other Dapr applications from a Rust application. The Dapr client package allows you to interact with other Dapr applications from
a Rust application.
{{% alert title="Note" color="primary" %}} {{% alert title="Note" color="primary" %}}
The Dapr Rust-SDK is currently in Alpha. Work is underway to bring it to a stable release and will likely involve breaking changes. The Dapr Rust-SDK is currently in Alpha. Work is underway to bring it to a
stable release and will likely involve breaking changes.
{{% /alert %}} {{% /alert %}}
## Prerequisites ## Prerequisites
- [Dapr CLI]({{< ref install-dapr-cli.md >}}) installed - [Dapr CLI]({{% ref install-dapr-cli.md %}}) installed
- Initialized [Dapr environment]({{< ref install-dapr-selfhost.md >}}) - Initialized [Dapr environment]({{% ref install-dapr-selfhost.md %}})
- [Rust installed](https://www.rust-lang.org/tools/install) - [Rust installed](https://www.rust-lang.org/tools/install)
## Import the client package ## Import the client package
Add Dapr to your `cargo.toml` Add Dapr to your `cargo.toml`
@ -27,34 +28,42 @@ Add Dapr to your `cargo.toml`
```toml ```toml
[dependencies] [dependencies]
# Other dependencies # Other dependencies
dapr = "0.13.0" dapr = "0.16.0"
``` ```
You can either reference `dapr::Client` or bind the full path to a new name as follows: You can either reference `dapr::Client` or bind the full path to a new name as follows:
```rust ```rust
use dapr::Client as DaprClient use dapr::Client as DaprClient;
``` ```
## Instantiating the Dapr client ## Instantiating the Dapr client
```rust ```rust
const addr: String = "https://127.0.0.1"; let addr = "https://127.0.0.1".to_string();
const port: String = "50001";
let mut client = dapr::Client::<dapr::client::TonicClient>::connect(addr, let mut client = dapr::Client::<dapr::client::TonicClient>::connect(addr,
port).await?; port).await?;
``` ```
Alternatively if you would like to specify a custom port, this can be done by using this connect method:
```rust
let mut client = dapr::Client::<dapr::client::TonicClient>::connect_with_port(addr, "3500".to_string()).await?;
```
## Building blocks ## Building blocks
The Rust SDK allows you to interface with the [Dapr building blocks]({{< ref building-blocks >}}). The Rust SDK allows you to interface with the
[Dapr building blocks]({{% ref building-blocks %}}).
### Service Invocation ### Service Invocation (gRPC)
To invoke a specific method on another service running with Dapr sidecar, the Dapr client Go SDK provides two options: To invoke a specific method on another service running with Dapr sidecar, the
Dapr client provides two options:
Invoke a (gRPC) service
Invoke a service
```rust ```rust
let response = client let response = client
.invoke_service("service-to-invoke", "method-to-invoke", Some(data)) .invoke_service("service-to-invoke", "method-to-invoke", Some(data))
@ -62,36 +71,43 @@ let response = client
.unwrap(); .unwrap();
``` ```
For a full guide on service invocation, visit
For a full guide on service invocation, visit [How-To: Invoke a service]({{< ref howto-invoke-discover-services.md >}}). [How-To: Invoke a service]({{% ref howto-invoke-discover-services.md %}}).
### State Management ### State Management
The Dapr Client provides access to these state management methods: `save_state`, `get_state`, `delete_state` that can be used like so: The Dapr Client provides access to these state management methods: `save_state`
, `get_state`, `delete_state` that can be used like so:
```rust ```rust
let store_name = "store-name"; let store_name = String::from("statestore");
let state_key = "state-key";
let states = vec![(state_key, ("state-value").as_bytes().to_vec())]; let key = String::from("hello");
let val = String::from("world").into_bytes();
// save state with the key "state-key" and value "state-value" // save key-value pair in the state store
client.save_state(store_name, states).await?; client
.save_state(store_name, key, val, None, None, None)
.await?;
// get state for key "state-key" let get_response = client
let response = client.get_state(store_name, state_key, None).await.unwrap(); .get_state("statestore", "hello", None)
.await?;
// delete state for key "state-key" // delete a value from the state store
client.delete_state(store_name, state_key, None).await?; client
.delete_state("statestore", "hello", None)
.await?;
``` ```
> **Note:** The `save_state` method currently performs a 'bulk' save but this will be refactored Multiple states can be sent with the `save_bulk_states` method.
For a full guide on state management, visit
For a full guide on state management, visit [How-To: Save & get state]({{< ref howto-get-save-state.md >}}). [How-To: Save & get state]({{% ref howto-get-save-state.md %}}).
### Publish Messages ### Publish Messages
To publish data onto a topic, the Dapr Go client provides a simple method:
To publish data onto a topic, the Dapr client provides a simple method:
```rust ```rust
let pubsub_name = "pubsub-name".to_string(); let pubsub_name = "pubsub-name".to_string();
@ -104,7 +120,9 @@ client
.await?; .await?;
``` ```
For a full guide on pub/sub, visit [How-To: Publish & subscribe]({{< ref howto-publish-subscribe.md >}}). For a full guide on pub/sub, visit
[How-To: Publish & subscribe]({{% ref howto-publish-subscribe.md %}}).
## Related links ## Related links
[Rust SDK Examples](https://github.com/dapr/rust-sdk/tree/master/examples) [Rust SDK Examples](https://github.com/dapr/rust-sdk/tree/master/examples)

95
examples/Cargo.toml Normal file
View File

@ -0,0 +1,95 @@
[package]
name = "examples"
authors.workspace = true
license.workspace = true
edition.workspace = true
publish = false
version = "0.0.1"
repository.workspace = true
rust-version.workspace = true
[dependencies]
async-trait = { workspace = true }
dapr = { path = "../dapr" }
dapr-macros = { path = "../dapr-macros" }
env_logger = "0.11"
log = "0.4"
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
tokio = { workspace = true, features = ["full"] }
tokio-stream = { workspace = true }
tonic = { workspace = true }
prost = { workspace = true }
prost-types = { workspace = true }
[[example]]
name = "actors-client"
path = "src/actors/client.rs"
[[example]]
name = "actors-server"
path = "src/actors/server.rs"
[[example]]
name = "bindings-input"
path = "src/bindings/input.rs"
[[example]]
name = "bindings-output"
path = "src/bindings/output.rs"
[[example]]
name = "client"
path = "src/client/client.rs"
[[example]]
name = "configuration"
path = "src/configuration/main.rs"
[[example]]
name = "conversation"
path = "src/conversation/main.rs"
[[example]]
name = "crypto"
path = "src/crypto/main.rs"
[[example]]
name = "invoke-grpc-client"
path = "src/invoke/grpc/client.rs"
[[example]]
name = "invoke-grpc-server"
path = "src/invoke/grpc/server.rs"
[[example]]
name = "invoke-grpc-proxying-client"
path = "src/invoke/grpc-proxying/client.rs"
[[example]]
name = "invoke-grpc-proxying-server"
path = "src/invoke/grpc-proxying/server.rs"
[[example]]
name = "jobs"
path = "src/jobs/jobs.rs"
[[example]]
name = "pubsub-publisher"
path = "src/pubsub/publisher.rs"
[[example]]
name = "pubsub-subscriber"
path = "src/pubsub/subscriber.rs"
[[example]]
name = "query-state-1"
path = "src/query_state/query1.rs"
[[example]]
name = "query-state-2"
path = "src/query_state/query2.rs"
[[example]]
name = "secrets-bulk"
path = "src/secrets-bulk/app.rs"

View File

@ -2,9 +2,9 @@
These examples demonstrates how to use Dapr rust sdk. These examples demonstrates how to use Dapr rust sdk.
* [client](./client) * [client](src/client)
* Simple dapr client example that saves, gets, and deletes state from the state stores * Simple dapr client example that saves, gets, and deletes state from the state stores
* [pubsub](./pubsub) * [pubsub](src/pubsub)
* Publishes and subscribes to events * Publishes and subscribes to events
## Adding new examples ## Adding new examples

View File

@ -88,7 +88,22 @@ Use the `DaprJson` extractor to deserialize the request from Json coming from a
> docker ps > docker ps
> ``` > ```
To run this example (using the multi-app run): 1. To run the example we need to first build the examples using the following command:
<!-- STEP
name: Build
background: false
sleep: 30
timeout: 60
-->
```bash
cargo build --examples
```
<!-- END_STEP -->
2. Run this example (using the multi-app run):
<!-- STEP <!-- STEP
@ -120,11 +135,11 @@ dapr run -f .
1. Start actor host (expose Http server receiver on port 50051): 1. Start actor host (expose Http server receiver on port 50051):
```bash ```bash
dapr run --app-id actor-host --app-protocol http --app-port 50051 cargo run -- --example actor-server dapr run --app-id actor-host --app-protocol http --app-port 50051 cargo run -- --example actors-server
``` ```
2. Start actor client: 2. Start actor client:
```bash ```bash
dapr run --app-id actor-client --dapr-grpc-port 3502 cargo run -- --example actor-client dapr run --app-id actor-client --dapr-grpc-port 3502 cargo run -- --example actors-client
``` ```

View File

@ -14,7 +14,7 @@ pub struct MyRequest {
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
// TODO: Handle this issue in the sdk // TODO: Handle this issue in the sdk
// Introduce delay so that dapr grpc port is assigned before app tries to connect // Introduce delay so that dapr grpc port is assigned before app tries to connect
std::thread::sleep(std::time::Duration::new(2, 0)); tokio::time::sleep(std::time::Duration::new(2, 0)).await;
// Define the Dapr address // Define the Dapr address
let addr = "https://127.0.0.1".to_string(); let addr = "https://127.0.0.1".to_string();
@ -30,7 +30,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.invoke_actor("MyActor", "a1", "do_stuff", data, None) .invoke_actor("MyActor", "a1", "do_stuff", data, None)
.await; .await;
println!("Response: {:#?}", resp); println!("Response: {resp:#?}");
Ok(()) Ok(())
} }

View File

@ -8,9 +8,9 @@ apps:
appProtocol: http appProtocol: http
appPort: 50051 appPort: 50051
logLevel: debug logLevel: debug
command: ["cargo", "run", "--example", "actor-server"] command: ["cargo", "run", "--example", "actors-server"]
- appID: actor-client - appID: actor-client
appDirPath: ./ appDirPath: ./
daprGRPCPort: 3502 daprGRPCPort: 3502
logLevel: debug logLevel: debug
command: ["cargo", "run", "--example", "actor-client"] command: ["cargo", "run", "--example", "actors-client"]

View File

@ -31,7 +31,7 @@ impl MyActor {
println!("doing stuff with {}", req.name); println!("doing stuff with {}", req.name);
let mut dapr = self.client.clone(); let mut dapr = self.client.clone();
let r = dapr.get_actor_state("key1").await.unwrap(); let r = dapr.get_actor_state("key1").await.unwrap();
println!("get_actor_state {:?}", r); println!("get_actor_state {r:?}");
Json(MyResponse { available: true }) Json(MyResponse { available: true })
} }
} }

View File

@ -12,9 +12,22 @@ In order to have both examples working with the same binding configuration Servi
## Running ## Running
To run this example: 1. To run the example we need to first build the examples using the following command:
1. Run a kafka container <!-- STEP
name: Build
background: false
sleep: 30
timeout: 60
-->
```bash
cargo build --examples
```
<!-- END_STEP -->
2Run a kafka container
<!-- STEP <!-- STEP
name: Run kafka instance name: Run kafka instance
@ -31,7 +44,7 @@ docker run -p 9092:9092 apache/kafka:3.7.1
<!-- END_STEP --> <!-- END_STEP -->
2. Run the multi-app run template (`dapr.yaml`) 3. Run the multi-app run template (`dapr.yaml`)
<!-- STEP <!-- STEP
name: Run Multi-app Run name: Run Multi-app Run
@ -60,7 +73,7 @@ expected_stdout_lines:
- '== APP - rust-input-b == Message: 9 => hello from rust!' - '== APP - rust-input-b == Message: 9 => hello from rust!'
background: true background: true
sleep: 30 sleep: 30
timeout_seconds: 90 timeout_seconds: 30
--> -->
```bash ```bash

View File

@ -8,9 +8,9 @@ apps:
appProtocol: grpc appProtocol: grpc
appPort: 50051 appPort: 50051
logLevel: debug logLevel: debug
command: ["cargo", "run", "--example", "input-bindings"] command: ["cargo", "run", "--example", "bindings-input"]
- appID: rust-output-b - appID: rust-output-b
appDirPath: ./ appDirPath: ./
appProtocol: grpc appProtocol: grpc
logLevel: debug logLevel: debug
command: ["cargo", "run", "--example", "output-bindings"] command: ["cargo", "run", "--example", "bindings-output"]

View File

@ -1,8 +1,8 @@
use tonic::{transport::Server, Request, Response, Status}; use tonic::{transport::Server, Request, Response, Status};
use dapr::dapr::dapr::proto::common::v1::{InvokeRequest, InvokeResponse}; use dapr::dapr::proto::common::v1::{InvokeRequest, InvokeResponse};
use dapr::dapr::dapr::proto::runtime::v1::app_callback_server::{AppCallback, AppCallbackServer}; use dapr::dapr::proto::runtime::v1::{
use dapr::dapr::dapr::proto::runtime::v1::{ app_callback_server::{AppCallback, AppCallbackServer},
BindingEventRequest, BindingEventResponse, ListInputBindingsResponse, BindingEventRequest, BindingEventResponse, ListInputBindingsResponse,
ListTopicSubscriptionsResponse, TopicEventRequest, TopicEventResponse, ListTopicSubscriptionsResponse, TopicEventRequest, TopicEventResponse,
}; };
@ -61,7 +61,7 @@ impl AppCallback for AppCallbackService {
let name = &r.name; let name = &r.name;
let data = &r.data; let data = &r.data;
let message = String::from_utf8_lossy(&data); let message = String::from_utf8_lossy(data);
println!("Binding Name: {}", &name); println!("Binding Name: {}", &name);
println!("Message: {}", &message); println!("Message: {}", &message);
@ -75,7 +75,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let callback_service = AppCallbackService::default(); let callback_service = AppCallbackService::default();
println!("AppCallback server listening on: {}", addr); println!("AppCallback server listening on: {addr}");
// Create a gRPC server with the callback_service. // Create a gRPC server with the callback_service.
Server::builder() Server::builder()

View File

@ -1,10 +1,10 @@
use std::{collections::HashMap, thread, time::Duration}; use std::{collections::HashMap, time::Duration};
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
// TODO: Handle this issue in the sdk // TODO: Handle this issue in the sdk
// Introduce delay so that dapr grpc port is assigned before app tries to connect // Introduce delay so that dapr grpc port is assigned before app tries to connect
thread::sleep(Duration::from_secs(2)); tokio::time::sleep(Duration::from_secs(2)).await;
// Get the Dapr port and create a connection // Get the Dapr port and create a connection
let addr = "https://127.0.0.1".to_string(); let addr = "https://127.0.0.1".to_string();

View File

@ -5,10 +5,19 @@ docker ps
1. To run the example we need to first build the examples using the following command: 1. To run the example we need to first build the examples using the following command:
``` <!-- STEP
name: Build
background: false
sleep: 30
timeout: 60
-->
```bash
cargo build --examples cargo build --examples
``` ```
<!-- END_STEP -->
2. Run the example with dapr using the following command: 2. Run the example with dapr using the following command:
<!-- STEP <!-- STEP

View File

@ -2,7 +2,7 @@
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
// TODO: Handle this issue in the sdk // TODO: Handle this issue in the sdk
// Introduce delay so that dapr grpc port is assigned before app tries to connect // Introduce delay so that dapr grpc port is assigned before app tries to connect
std::thread::sleep(std::time::Duration::new(2, 0)); tokio::time::sleep(std::time::Duration::new(2, 0)).await;
// Set the Dapr address // Set the Dapr address
let addr = "https://127.0.0.1".to_string(); let addr = "https://127.0.0.1".to_string();
@ -17,7 +17,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let store_name = String::from("statestore"); let store_name = String::from("statestore");
// save key-value pair in the state store // save key-value pair in the state store
client.save_state(store_name, vec![(key, val)]).await?; client
.save_state(store_name, key, val, None, None, None)
.await?;
println!("Successfully saved!"); println!("Successfully saved!");

View File

@ -5,10 +5,19 @@ docker ps
1. To run the example we need to first build the examples using the following command: 1. To run the example we need to first build the examples using the following command:
<!-- STEP
name: Build
background: false
sleep: 30
timeout: 60
-->
```bash ```bash
cargo build --examples cargo build --examples
``` ```
<!-- END_STEP -->
2. Insert a key with the value `hello` to redis using the following command: 2. Insert a key with the value `hello` to redis using the following command:

View File

@ -7,7 +7,7 @@ type DaprClient = dapr::Client<dapr::client::TonicClient>;
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
// TODO: Handle this issue in the sdk // TODO: Handle this issue in the sdk
// Introduce delay so that dapr grpc port is assigned before app tries to connect // Introduce delay so that dapr grpc port is assigned before app tries to connect
std::thread::sleep(std::time::Duration::new(2, 0)); tokio::time::sleep(std::time::Duration::new(2, 0)).await;
// Set the Dapr address // Set the Dapr address
let addr = "https://127.0.0.1".to_string(); let addr = "https://127.0.0.1".to_string();
@ -19,14 +19,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// get key-value pair in the state store // get key-value pair in the state store
let response = client let response = client
.get_configuration(CONFIGSTORE_NAME, vec![(&key)], None) .get_configuration(CONFIGSTORE_NAME, vec![&key], None)
.await?; .await?;
let val = response.items.get("hello").unwrap(); let val = response.items.get("hello").unwrap();
println!("Configuration value: {val:?}"); println!("Configuration value: {val:?}");
// Subscribe for configuration changes // Subscribe for configuration changes
let mut stream = client let mut stream = client
.subscribe_configuration(CONFIGSTORE_NAME, vec![(&key)], None) .subscribe_configuration(CONFIGSTORE_NAME, vec![&key], None)
.await?; .await?;
let mut subscription_id = String::new(); let mut subscription_id = String::new();
@ -52,7 +52,7 @@ async fn unsubscribe(client: &mut DaprClient, subscription_id: &str) {
.await .await
{ {
Ok(_) => println!("App unsubscribed from config changes"), Ok(_) => println!("App unsubscribed from config changes"),
Err(e) => println!("Error unsubscribing from config updates: {}", e), Err(e) => println!("Error unsubscribing from config updates: {e}"),
} }
std::process::exit(0); std::process::exit(0);
} }

View File

@ -0,0 +1,53 @@
# Dapr Conversation Example with the Rust-SDK
This example uses the echo component to send a request and the component response will be the exact message received.
## Step
### Prepare
- Dapr installed
### Run Conversation Example
1. To run the example we need to first build the examples using the following command:
<!-- STEP
name: Build
background: false
sleep: 30
timeout: 60
-->
```bash
cargo build --examples
```
<!-- END_STEP -->
2. Run the example using the Dapr CLI
<!-- STEP
name: Run Conversation
output_match_mode: substring
expected_stdout_lines:
- 'conversation input: "hello world"'
- 'conversation output: "hello world"'
background: true
sleep: 15
timeout_seconds: 30
-->
```bash
dapr run --app-id=conversation --resources-path ./config --dapr-grpc-port 3500 -- cargo run --example conversation
```
<!-- END_STEP -->
## Result
```
- 'conversation input: hello world'
- 'conversation output: hello world'
```

View File

@ -0,0 +1,7 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: echo
spec:
type: conversation.echo
version: v1

View File

@ -0,0 +1,30 @@
use dapr::client::{ConversationInputBuilder, ConversationRequestBuilder};
use std::time::Duration;
type DaprClient = dapr::Client<dapr::client::TonicClient>;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Sleep to allow for the server to become available
tokio::time::sleep(Duration::from_secs(5)).await;
// Set the Dapr address
let address = "https://127.0.0.1".to_string();
let port = "3500".to_string();
let mut client = DaprClient::connect_with_port(address, port).await?;
let input = ConversationInputBuilder::new("hello world").build();
let conversation_component = "echo";
let request =
ConversationRequestBuilder::new(conversation_component, vec![input.clone()]).build();
println!("conversation input: {:?}", input.content);
let response = client.converse_alpha1(request).await?;
println!("conversation output: {:?}", response.outputs[0].result);
Ok(())
}

View File

@ -6,15 +6,30 @@ This is a simple example that demonstrates Dapr's Cryptography capabilities.
## Running ## Running
To run this example: 1. To run the example we need to first build the examples using the following command:
<!-- STEP
name: Build
background: false
sleep: 30
timeout: 60
-->
```bash
cargo build --examples
```
<!-- END_STEP -->
2. Generate keys in examples/crypto/keys directory:
1. Generate keys in examples/crypto/keys directory:
<!-- STEP <!-- STEP
name: Generate keys name: Generate keys
background: false background: false
sleep: 5 sleep: 5
timeout_seconds: 30 timeout_seconds: 30
--> -->
```bash ```bash
mkdir -p keys mkdir -p keys
# Generate a private RSA key, 4096-bit keys # Generate a private RSA key, 4096-bit keys
@ -25,7 +40,7 @@ openssl rand -out keys/symmetric-key-256 32
<!-- END_STEP --> <!-- END_STEP -->
2. Run the multi-app run template: 3. Run the multi-app run template:
<!-- STEP <!-- STEP
name: Run multi-app name: Run multi-app
@ -36,7 +51,7 @@ expected_stdout_lines:
- '== APP - crypto-example == Successfully Decrypted Image' - '== APP - crypto-example == Successfully Decrypted Image'
background: true background: true
sleep: 30 sleep: 30
timeout_seconds: 90 timeout_seconds: 30
--> -->
```bash ```bash
@ -45,4 +60,4 @@ dapr run -f .
<!-- END_STEP --> <!-- END_STEP -->
2. Stop with `ctrl + c` 4. Stop with `ctrl + c`

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -5,10 +5,19 @@ docker ps
1. To run the example we need to first build the examples using the following command: 1. To run the example we need to first build the examples using the following command:
``` <!-- STEP
name: Build
background: false
sleep: 30
timeout: 60
-->
```bash
cargo build --examples cargo build --examples
``` ```
<!-- END_STEP -->
2. Run the example with dapr using the following command: 2. Run the example with dapr using the following command:
<!-- STEP <!-- STEP
@ -22,7 +31,7 @@ expected_stdout_lines:
- '== APP - invoke-grpc-client == }' - '== APP - invoke-grpc-client == }'
background: true background: true
sleep: 30 sleep: 30
timeout_seconds: 90 timeout_seconds: 30
--> -->
```bash ```bash

View File

@ -1,21 +1,21 @@
use std::{thread, time::Duration}; use std::time::Duration;
use hello_world::{greeter_client::GreeterClient, HelloRequest}; use hello_world::{greeter_client::GreeterClient, HelloRequest};
use tonic::metadata::MetadataValue; use tonic::metadata::MetadataValue;
pub mod hello_world { pub mod hello_world {
tonic::include_proto!("helloworld"); // The string specified here must match the proto package name include!("../protos/helloworld.rs");
} }
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Sleep to allow for the server to become available // Sleep to allow for the server to become available
thread::sleep(Duration::from_secs(5)); tokio::time::sleep(Duration::from_secs(5)).await;
// Get the Dapr port and create a connection // Get the Dapr port and create a connection
let port: u16 = std::env::var("DAPR_GRPC_PORT").unwrap().parse().unwrap(); let port: u16 = std::env::var("DAPR_GRPC_PORT").unwrap().parse().unwrap();
let address = format!("https://127.0.0.1:{}", port); let address = format!("https://127.0.0.1:{port}");
let mut client = GreeterClient::connect(address).await?; let mut client = GreeterClient::connect(address).await?;
@ -31,7 +31,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let response = client.say_hello(request).await.unwrap(); let response = client.say_hello(request).await.unwrap();
let hello_reply = response.into_inner(); let hello_reply = response.into_inner();
println!("Response: {:#?}", hello_reply); println!("Response: {hello_reply:#?}");
Ok(()) Ok(())
} }

View File

@ -3,7 +3,7 @@ use crate::hello_world::{HelloReply, HelloRequest};
use tonic::{transport::Server, Request, Response, Status}; use tonic::{transport::Server, Request, Response, Status};
pub mod hello_world { pub mod hello_world {
tonic::include_proto!("helloworld"); // The string specified here must match the proto package name include!("../protos/helloworld.rs");
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -33,7 +33,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let greeter_service = GreeterService::default(); let greeter_service = GreeterService::default();
println!("AppCallback server listening on: {}", server_address); println!("AppCallback server listening on: {server_address}");
// Create a gRPC server with the callback_service. // Create a gRPC server with the callback_service.
Server::builder() Server::builder()
.add_service(GreeterServer::new(greeter_service)) .add_service(GreeterServer::new(greeter_service))

View File

@ -5,10 +5,19 @@ docker ps
1. To run the example we need to first build the examples using the following command: 1. To run the example we need to first build the examples using the following command:
``` <!-- STEP
name: Build
background: false
sleep: 30
timeout: 60
-->
```bash
cargo build --examples cargo build --examples
``` ```
<!-- END_STEP -->
2. Run the example with dapr using the following command to start the multi-app run: 2. Run the example with dapr using the following command to start the multi-app run:
<!-- STEP <!-- STEP
@ -45,7 +54,7 @@ expected_stdout_lines:
- '== APP - invoke-grpc-client == }' - '== APP - invoke-grpc-client == }'
background: true background: true
sleep: 30 sleep: 30
timeout_seconds: 90 timeout_seconds: 30
--> -->
== APP - invoke-grpc-server == Method: say_hello == APP - invoke-grpc-server == Method: say_hello
== APP - invoke-grpc-server == Name: "Test" == APP - invoke-grpc-server == Name: "Test"

View File

@ -1,10 +1,10 @@
use std::{thread, time::Duration}; use crate::hello_world::HelloReply;
use std::time::Duration;
use hello_world::{HelloReply, HelloRequest};
use prost::Message; use prost::Message;
pub mod hello_world { pub mod hello_world {
tonic::include_proto!("helloworld"); // The string specified here must match the proto package name include!("../protos/helloworld.rs");
} }
type DaprClient = dapr::Client<dapr::client::TonicClient>; type DaprClient = dapr::Client<dapr::client::TonicClient>;
@ -12,14 +12,14 @@ type DaprClient = dapr::Client<dapr::client::TonicClient>;
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Sleep to allow for the server to become available // Sleep to allow for the server to become available
thread::sleep(Duration::from_secs(5)); tokio::time::sleep(Duration::from_secs(5)).await;
// Set the Dapr address // Set the Dapr address
let address = "https://127.0.0.1".to_string(); let address = "https://127.0.0.1".to_string();
let mut client = DaprClient::connect(address).await?; let mut client = DaprClient::connect(address).await?;
let request = HelloRequest { let request = hello_world::HelloRequest {
name: "Test".to_string(), name: "Test".to_string(),
}; };
let data = request.encode_to_vec(); let data = request.encode_to_vec();
@ -39,7 +39,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Message: {:#?}", &resp.message); println!("Message: {:#?}", &resp.message);
}; };
println!("Response: {:#?}", response); println!("Response: {response:#?}");
Ok(()) Ok(())
} }

View File

@ -1,14 +1,15 @@
use dapr::{ use dapr::{
appcallback::*, appcallback::*,
dapr::dapr::proto::runtime::v1::app_callback_server::{AppCallback, AppCallbackServer}, dapr::proto::runtime::v1::app_callback_server::{AppCallback, AppCallbackServer},
}; };
use prost::Message;
use tonic::{transport::Server, Request, Response, Status}; use tonic::{transport::Server, Request, Response, Status};
use prost::Message;
use hello_world::{HelloReply, HelloRequest}; use hello_world::{HelloReply, HelloRequest};
pub mod hello_world { pub mod hello_world {
tonic::include_proto!("helloworld"); // The string specified here must match the proto package name include!("../protos/helloworld.rs");
} }
pub struct AppCallbackService {} pub struct AppCallbackService {}
@ -96,7 +97,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let callback_service = AppCallbackService {}; let callback_service = AppCallbackService {};
println!("AppCallback server listening on: {}", server_address); println!("AppCallback server listening on: {server_address}");
// Create a gRPC server with the callback_service. // Create a gRPC server with the callback_service.
Server::builder() Server::builder()
.add_service(AppCallbackServer::new(callback_service)) .add_service(AppCallbackServer::new(callback_service))

View File

@ -0,0 +1,300 @@
// This file is @generated by prost-build.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct HelloRequest {
#[prost(string, tag = "1")]
pub name: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct HelloReply {
#[prost(string, tag = "1")]
pub message: ::prost::alloc::string::String,
}
/// Generated client implementations.
pub mod greeter_client {
#![allow(
unused_variables,
dead_code,
missing_docs,
clippy::wildcard_imports,
clippy::let_unit_value,
)]
use tonic::codegen::*;
use tonic::codegen::http::Uri;
#[derive(Debug, Clone)]
pub struct GreeterClient<T> {
inner: tonic::client::Grpc<T>,
}
impl GreeterClient<tonic::transport::Channel> {
/// Attempt to create a new client by connecting to a given endpoint.
pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>
where
D: TryInto<tonic::transport::Endpoint>,
D::Error: Into<StdError>,
{
let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;
Ok(Self::new(conn))
}
}
impl<T> GreeterClient<T>
where
T: tonic::client::GrpcService<tonic::body::BoxBody>,
T::Error: Into<StdError>,
T::ResponseBody: Body<Data = Bytes> + std::marker::Send + 'static,
<T::ResponseBody as Body>::Error: Into<StdError> + std::marker::Send,
{
pub fn new(inner: T) -> Self {
let inner = tonic::client::Grpc::new(inner);
Self { inner }
}
pub fn with_origin(inner: T, origin: Uri) -> Self {
let inner = tonic::client::Grpc::with_origin(inner, origin);
Self { inner }
}
pub fn with_interceptor<F>(
inner: T,
interceptor: F,
) -> GreeterClient<InterceptedService<T, F>>
where
F: tonic::service::Interceptor,
T::ResponseBody: Default,
T: tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
Response = http::Response<
<T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody,
>,
>,
<T as tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
>>::Error: Into<StdError> + std::marker::Send + std::marker::Sync,
{
GreeterClient::new(InterceptedService::new(inner, interceptor))
}
/// Compress requests with the given encoding.
///
/// This requires the server to support it otherwise it might respond with an
/// error.
#[must_use]
pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.inner = self.inner.send_compressed(encoding);
self
}
/// Enable decompressing responses.
#[must_use]
pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.inner = self.inner.accept_compressed(encoding);
self
}
/// Limits the maximum size of a decoded message.
///
/// Default: `4MB`
#[must_use]
pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
self.inner = self.inner.max_decoding_message_size(limit);
self
}
/// Limits the maximum size of an encoded message.
///
/// Default: `usize::MAX`
#[must_use]
pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
self.inner = self.inner.max_encoding_message_size(limit);
self
}
pub async fn say_hello(
&mut self,
request: impl tonic::IntoRequest<super::HelloRequest>,
) -> std::result::Result<tonic::Response<super::HelloReply>, tonic::Status> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/helloworld.Greeter/SayHello",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("helloworld.Greeter", "SayHello"));
self.inner.unary(req, path, codec).await
}
}
}
/// Generated server implementations.
pub mod greeter_server {
#![allow(
unused_variables,
dead_code,
missing_docs,
clippy::wildcard_imports,
clippy::let_unit_value,
)]
use tonic::codegen::*;
/// Generated trait containing gRPC methods that should be implemented for use with GreeterServer.
#[async_trait]
pub trait Greeter: std::marker::Send + std::marker::Sync + 'static {
async fn say_hello(
&self,
request: tonic::Request<super::HelloRequest>,
) -> std::result::Result<tonic::Response<super::HelloReply>, tonic::Status>;
}
#[derive(Debug)]
pub struct GreeterServer<T> {
inner: Arc<T>,
accept_compression_encodings: EnabledCompressionEncodings,
send_compression_encodings: EnabledCompressionEncodings,
max_decoding_message_size: Option<usize>,
max_encoding_message_size: Option<usize>,
}
impl<T> GreeterServer<T> {
pub fn new(inner: T) -> Self {
Self::from_arc(Arc::new(inner))
}
pub fn from_arc(inner: Arc<T>) -> Self {
Self {
inner,
accept_compression_encodings: Default::default(),
send_compression_encodings: Default::default(),
max_decoding_message_size: None,
max_encoding_message_size: None,
}
}
pub fn with_interceptor<F>(
inner: T,
interceptor: F,
) -> InterceptedService<Self, F>
where
F: tonic::service::Interceptor,
{
InterceptedService::new(Self::new(inner), interceptor)
}
/// Enable decompressing requests with the given encoding.
#[must_use]
pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.accept_compression_encodings.enable(encoding);
self
}
/// Compress responses with the given encoding, if the client supports it.
#[must_use]
pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.send_compression_encodings.enable(encoding);
self
}
/// Limits the maximum size of a decoded message.
///
/// Default: `4MB`
#[must_use]
pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
self.max_decoding_message_size = Some(limit);
self
}
/// Limits the maximum size of an encoded message.
///
/// Default: `usize::MAX`
#[must_use]
pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
self.max_encoding_message_size = Some(limit);
self
}
}
impl<T, B> tonic::codegen::Service<http::Request<B>> for GreeterServer<T>
where
T: Greeter,
B: Body + std::marker::Send + 'static,
B::Error: Into<StdError> + std::marker::Send + 'static,
{
type Response = http::Response<tonic::body::BoxBody>;
type Error = std::convert::Infallible;
type Future = BoxFuture<Self::Response, Self::Error>;
fn poll_ready(
&mut self,
_cx: &mut Context<'_>,
) -> Poll<std::result::Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: http::Request<B>) -> Self::Future {
match req.uri().path() {
"/helloworld.Greeter/SayHello" => {
#[allow(non_camel_case_types)]
struct SayHelloSvc<T: Greeter>(pub Arc<T>);
impl<T: Greeter> tonic::server::UnaryService<super::HelloRequest>
for SayHelloSvc<T> {
type Response = super::HelloReply;
type Future = BoxFuture<
tonic::Response<Self::Response>,
tonic::Status,
>;
fn call(
&mut self,
request: tonic::Request<super::HelloRequest>,
) -> Self::Future {
let inner = Arc::clone(&self.0);
let fut = async move {
<T as Greeter>::say_hello(&inner, request).await
};
Box::pin(fut)
}
}
let accept_compression_encodings = self.accept_compression_encodings;
let send_compression_encodings = self.send_compression_encodings;
let max_decoding_message_size = self.max_decoding_message_size;
let max_encoding_message_size = self.max_encoding_message_size;
let inner = self.inner.clone();
let fut = async move {
let method = SayHelloSvc(inner);
let codec = tonic::codec::ProstCodec::default();
let mut grpc = tonic::server::Grpc::new(codec)
.apply_compression_config(
accept_compression_encodings,
send_compression_encodings,
)
.apply_max_message_size_config(
max_decoding_message_size,
max_encoding_message_size,
);
let res = grpc.unary(method, req).await;
Ok(res)
};
Box::pin(fut)
}
_ => {
Box::pin(async move {
let mut response = http::Response::new(empty_body());
let headers = response.headers_mut();
headers
.insert(
tonic::Status::GRPC_STATUS,
(tonic::Code::Unimplemented as i32).into(),
);
headers
.insert(
http::header::CONTENT_TYPE,
tonic::metadata::GRPC_CONTENT_TYPE,
);
Ok(response)
})
}
}
}
}
impl<T> Clone for GreeterServer<T> {
fn clone(&self) -> Self {
let inner = self.inner.clone();
Self {
inner,
accept_compression_encodings: self.accept_compression_encodings,
send_compression_encodings: self.send_compression_encodings,
max_decoding_message_size: self.max_decoding_message_size,
max_encoding_message_size: self.max_encoding_message_size,
}
}
}
/// Generated gRPC service name
pub const SERVICE_NAME: &str = "helloworld.Greeter";
impl<T> tonic::server::NamedService for GreeterServer<T> {
const NAME: &'static str = SERVICE_NAME;
}
}

Binary file not shown.

View File

@ -6,7 +6,22 @@ This is a simple example that demonstrates Dapr's job scheduling capabilities.
To run this example: To run this example:
1. Run the multi-app run template: 1. To run the example we need to first build the examples using the following command:
<!-- STEP
name: Build
background: false
sleep: 30
timeout: 60
-->
```bash
cargo build --examples
```
<!-- END_STEP -->
2. Run the multi-app run template:
<!-- STEP <!-- STEP
name: Run multi-app name: Run multi-app
@ -33,4 +48,4 @@ dapr run -f .
<!-- END_STEP --> <!-- END_STEP -->
2. Stop with `ctrl + c` 3. Stop with `ctrl + c`

View File

@ -7,4 +7,5 @@ apps:
appProtocol: grpc appProtocol: grpc
appPort: 50051 appPort: 50051
logLevel: debug logLevel: debug
schedulerHostAddress: localhost
command: [ "cargo", "run", "--example", "jobs" ] command: [ "cargo", "run", "--example", "jobs" ]

View File

@ -1,11 +1,11 @@
use std::time::Duration; use std::time::Duration;
use base64::prelude::*;
use dapr::add_job_handler_alpha;
use dapr::client::JobBuilder; use dapr::client::JobBuilder;
use dapr::dapr::dapr::proto::runtime::v1::app_callback_alpha_server::AppCallbackAlphaServer; use dapr::dapr::proto::runtime::v1::{
use dapr::dapr::dapr::proto::runtime::v1::{JobEventRequest, JobEventResponse}; app_callback_alpha_server::AppCallbackAlphaServer, JobEventRequest, JobEventResponse,
};
use dapr::server::appcallbackalpha::{AppCallbackServiceAlpha, JobHandlerMethod}; use dapr::server::appcallbackalpha::{AppCallbackServiceAlpha, JobHandlerMethod};
use dapr::{add_job_handler_alpha, serde_json};
use prost_types::Any; use prost_types::Any;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tokio::time::sleep; use tokio::time::sleep;
@ -41,19 +41,10 @@ async fn backup_job_handler(request: JobEventRequest) -> Result<JobEventResponse
// The logic for handling the backup job request // The logic for handling the backup job request
if request.data.is_some() { if request.data.is_some() {
// weird value - any type is actually put into the value
let any = request.data.unwrap().value;
// parse any value
let any_parsed: JsonAny = serde_json::from_slice(&any).unwrap();
// Decode the base64-encoded value field
let decoded_value = BASE64_STANDARD.decode(any_parsed.value).unwrap();
// Deserialize the decoded value into a Backup struct // Deserialize the decoded value into a Backup struct
let backup_val: Backup = serde_json::from_slice(&decoded_value).unwrap(); let backup_val: Backup = serde_json::from_slice(&request.data.unwrap().value).unwrap();
println!("job received: {:?}", backup_val); println!("job received: {backup_val:?}");
} }
Ok(JobEventResponse::default()) Ok(JobEventResponse::default())
@ -97,9 +88,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client_addr = "https://127.0.0.1".to_string(); let client_addr = "https://127.0.0.1".to_string();
let port: u16 = std::env::var("DAPR_GRPC_PORT")?.parse()?; let port: u16 = std::env::var("DAPR_GRPC_PORT")?.parse()?;
let address = format!("{}:{}", client_addr, port); let address = format!("{client_addr}:{port}");
println!("attempting to create a dapr client: {}", address); println!("attempting to create a dapr client: {address}");
// Create the client // Create the client
let mut client = DaprClient::connect(client_addr).await?; let mut client = DaprClient::connect(client_addr).await?;
@ -136,7 +127,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let get_resp_backup: Backup = let get_resp_backup: Backup =
serde_json::from_slice(&get_resp.clone().job.unwrap().data.unwrap().value).unwrap(); serde_json::from_slice(&get_resp.clone().job.unwrap().data.unwrap().value).unwrap();
println!("job retrieved: {:?}", get_resp_backup); println!("job retrieved: {get_resp_backup:?}");
let _delete_resp = client.delete_job_alpha1("prod-db-backup").await?; let _delete_resp = client.delete_job_alpha1("prod-db-backup").await?;

View File

@ -14,12 +14,25 @@ This is a simple example that demonstrates Dapr's pub/sub capabilities. To imple
> docker ps > docker ps
> ``` > ```
To run this example: 1. To run the example we need to first build the examples using the following command:
1. Run the multi-app run template:
<!-- STEP <!-- STEP
name: Run Subscriber name: Build
background: false
sleep: 30
timeout: 60
-->
```bash
cargo build --examples
```
<!-- END_STEP -->
2. Run the multi-app run template:
<!-- STEP
name: Run PubSub example
output_match_mode: substring output_match_mode: substring
match_order: sequential match_order: sequential
expected_stdout_lines: expected_stdout_lines:
@ -104,9 +117,9 @@ expected_stdout_lines:
- '== APP - rust-subscriber == refund_amount: 1200,' - '== APP - rust-subscriber == refund_amount: 1200,'
- '== APP - rust-subscriber == }' - '== APP - rust-subscriber == }'
- '== APP - rust-publisher == messages published' - '== APP - rust-publisher == messages published'
background: true background: false
sleep: 30 sleep: 30
timeout_seconds: 90 timeout_seconds: 30
--> -->
@ -116,16 +129,16 @@ dapr run -f .
<!-- END_STEP --> <!-- END_STEP -->
2. Stop with `ctrl + c` 3. Stop with `ctrl + c`
### Running without multi-app ### Running without multi-app
1. Run the subscriber with dapr 1. Run the subscriber with dapr
```bash ```bash
dapr run --app-id rust-subscriber --app-protocol grpc --app-port 50051 cargo run -- --example subscriber dapr run --app-id rust-subscriber --app-protocol grpc --app-port 50051 cargo run -- --example pubsub-subscriber
``` ```
2. Run the publisher with dapr 2. Run the publisher with dapr
```bash ```bash
dapr run --app-id rust-publisher --app-protocol grpc cargo run -- --example publisher dapr run --app-id rust-publisher --app-protocol grpc cargo run -- --example pubsub-publisher
``` ```

View File

@ -8,9 +8,9 @@ apps:
appProtocol: grpc appProtocol: grpc
appPort: 50051 appPort: 50051
logLevel: debug logLevel: debug
command: ["cargo", "run", "--example", "subscriber"] command: ["cargo", "run", "--example", "pubsub-subscriber"]
- appID: rust-publisher - appID: rust-publisher
appDirPath: ./ appDirPath: ./
appProtocol: grpc appProtocol: grpc
logLevel: debug logLevel: debug
command: ["cargo", "run", "--example", "publisher"] command: ["cargo", "run", "--example", "pubsub-publisher"]

View File

@ -1,4 +1,6 @@
use std::{collections::HashMap, thread, time::Duration}; use std::{collections::HashMap, time::Duration};
use tokio::time;
use dapr::serde::{Deserialize, Serialize}; use dapr::serde::{Deserialize, Serialize};
use dapr::serde_json; use dapr::serde_json;
@ -19,7 +21,7 @@ struct Refund {
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
// TODO: Handle this issue in the sdk // TODO: Handle this issue in the sdk
// Introduce delay so that dapr grpc port is assigned before app tries to connect // Introduce delay so that dapr grpc port is assigned before app tries to connect
thread::sleep(Duration::from_secs(2)); tokio::time::sleep(Duration::from_secs(2)).await;
// Set address for Dapr connection // Set address for Dapr connection
let addr = "https://127.0.0.1".to_string(); let addr = "https://127.0.0.1".to_string();
@ -37,10 +39,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let topic = "A".to_string(); let topic = "A".to_string();
let topic_b = "B".to_string(); let topic_b = "B".to_string();
// Delay to wait for the subscriber to fully start
time::sleep(Duration::from_secs(5)).await;
for count in 0..10 { for count in 0..10 {
let order = Order { let order = Order {
order_number: count, order_number: count,
order_details: format!("Count is {}", count), order_details: format!("Count is {count}"),
}; };
// message metadata // message metadata
let mut metadata = HashMap::<String, String>::new(); let mut metadata = HashMap::<String, String>::new();

View File

@ -1,11 +1,8 @@
use dapr_macros::topic; use dapr_macros::topic;
use tonic::transport::Server; use tonic::transport::Server;
use dapr::appcallback::AppCallbackService;
use dapr::serde::{Deserialize, Serialize}; use dapr::serde::{Deserialize, Serialize};
use dapr::{ use dapr::{appcallback::*, dapr::proto::runtime::v1::app_callback_server::AppCallbackServer};
appcallback::*, dapr::dapr::proto::runtime::v1::app_callback_server::AppCallbackServer,
};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
struct Order { struct Order {
@ -21,12 +18,12 @@ struct Refund {
#[topic(pub_sub_name = "pubsub", topic = "A")] #[topic(pub_sub_name = "pubsub", topic = "A")]
async fn handle_a_event(order: Order) { async fn handle_a_event(order: Order) {
println!("Topic A - {:#?}", order) println!("Topic A - {order:#?}")
} }
#[topic(pub_sub_name = "pubsub", topic = "B")] #[topic(pub_sub_name = "pubsub", topic = "B")]
async fn handle_b_event(refund: Refund) { async fn handle_b_event(refund: Refund) {
println!("Topic B - {:#?}", refund) println!("Topic B - {refund:#?}")
} }
#[tokio::main] #[tokio::main]
@ -39,7 +36,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
callback_service.add_handler(HandleBEvent.get_handler()); callback_service.add_handler(HandleBEvent.get_handler());
println!("AppCallback server listening on: {}", addr); println!("AppCallback server listening on: {addr}");
// Create a gRPC server with the callback_service. // Create a gRPC server with the callback_service.
Server::builder() Server::builder()

View File

@ -50,10 +50,19 @@ curl -X POST -H "Content-Type: application/json" http://localhost:3500/v1.0/stat
1. To run the example we need to first build the examples using the following command: 1. To run the example we need to first build the examples using the following command:
<!-- STEP
name: Build
background: false
sleep: 30
timeout: 60
-->
```bash ```bash
cargo build --examples cargo build --examples
``` ```
<!-- END_STEP -->
2. Executing the first query 2. Executing the first query
Query: Query:
```json ```json
@ -83,7 +92,7 @@ sleep: 15
timeout_seconds: 30 timeout_seconds: 30
--> -->
```bash ```bash
dapr run --app-id=rustapp --dapr-grpc-port 3501 --resources-path statestore/ cargo run -- --example query_state_q1 dapr run --app-id=rustapp --dapr-grpc-port 3501 --resources-path statestore/ cargo run -- --example query-state-1
``` ```
<!-- END_STEP --> <!-- END_STEP -->
@ -117,7 +126,7 @@ sleep: 15
timeout_seconds: 30 timeout_seconds: 30
--> -->
```bash ```bash
dapr run --app-id=rustapp --dapr-grpc-port 3501 --resources-path statestore/ cargo run -- --example query_state_q2 dapr run --app-id=rustapp --dapr-grpc-port 3501 --resources-path statestore/ cargo run -- --example query-state-2
``` ```
<!-- END_STEP --> <!-- END_STEP -->

View File

@ -3,7 +3,7 @@ use serde_json::json;
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Introduce delay so that dapr grpc port is assigned before app tries to connect // Introduce delay so that dapr grpc port is assigned before app tries to connect
std::thread::sleep(std::time::Duration::new(5, 0)); tokio::time::sleep(std::time::Duration::new(5, 0)).await;
// Set the Dapr address and create a connection // Set the Dapr address and create a connection
let addr = "https://127.0.0.1".to_string(); let addr = "https://127.0.0.1".to_string();
@ -29,7 +29,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
{ {
Ok(response) => response.results, Ok(response) => response.results,
Err(e) => { Err(e) => {
println!("Error: {:?}", e); println!("Error: {e:?}");
return Ok(()); return Ok(());
} }
}; };
@ -43,7 +43,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
"value": value "value": value
})); }));
} }
println!("Query results: {:?}", results); println!("Query results: {results:?}");
Ok(()) Ok(())
} }

View File

@ -3,7 +3,7 @@ use serde_json::json;
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Introduce delay so that dapr grpc port is assigned before app tries to connect // Introduce delay so that dapr grpc port is assigned before app tries to connect
std::thread::sleep(std::time::Duration::new(5, 0)); tokio::time::sleep(std::time::Duration::new(5, 0)).await;
// Set the Dapr address and create a connection // Set the Dapr address and create a connection
let addr = "https://127.0.0.1".to_string(); let addr = "https://127.0.0.1".to_string();
@ -23,7 +23,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
{ {
Ok(response) => response.results, Ok(response) => response.results,
Err(e) => { Err(e) => {
println!("Error: {:?}", e); println!("Error: {e:?}");
return Ok(()); return Ok(());
} }
}; };
@ -37,7 +37,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
"value": value "value": value
})); }));
} }
println!("Query results: {:?}", results); println!("Query results: {results:?}");
Ok(()) Ok(())
} }

View File

@ -5,10 +5,19 @@ docker ps
1. To run the example we need to first build the examples using the following command: 1. To run the example we need to first build the examples using the following command:
``` <!-- STEP
name: Build
background: false
sleep: 30
timeout: 60
-->
```bash
cargo build --examples cargo build --examples
``` ```
<!-- END_STEP -->
2. Run the example with dapr using the following command: 2. Run the example with dapr using the following command:
<!-- STEP <!-- STEP

View File

@ -2,5 +2,5 @@
set -e set -e
echo "Home: $HOME" echo "Home: $HOME"
cd $1 cd src/$1
mm.py README.md mm.py README.md

View File

@ -1,17 +0,0 @@
[package]
name = "dapr-macros"
version = "0.15.0"
edition = "2021"
description = "Dapr Rust SDK"
license = "Apache-2.0"
[lib]
proc-macro = true
[dependencies]
async-trait = "0.1"
log = "0.4"
axum = "0.7.4"
syn = { version = "2.0.29", features = ["full"] }
quote = "1.0.8"
proc-macro2 = "1.0"

12
proto-gen/Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "proto-gen"
authors.workspace = true
license.workspace = true
edition.workspace = true
publish = false
repository.workspace = true
version.workspace = true
rust-version.workspace = true
[dependencies]
tonic-build = { workspace = true }

74
proto-gen/src/main.rs Normal file
View File

@ -0,0 +1,74 @@
use std::env;
use std::path::PathBuf;
fn main() {
let root_dir = {
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
manifest_dir.parent().unwrap().to_path_buf()
};
// dapr
// env::set_var("OUT_DIR", "src");
proto_gen(
root_dir.clone(),
true,
true,
"dapr/src/dapr",
&[
"proto/dapr/proto/common/v1/common.proto",
"proto/dapr/proto/runtime/v1/dapr.proto",
"proto/dapr/proto/runtime/v1/appcallback.proto",
],
&[
"proto",
"proto/dapr/proto/common/v1",
"proto/dapr/proto/runtime/v1",
],
);
// example - helloworld
proto_gen(
root_dir.clone(),
true,
true,
"examples/src/invoke/protos/",
&["examples/proto/helloworld/helloworld.proto"],
&["examples/proto/helloworld"],
);
}
fn proto_gen(
root_dir: PathBuf,
build_client: bool,
build_server: bool,
out_dir: &str,
include_dirs: &[&str],
interface: &[&str],
) {
let include_dirs = include_dirs
.iter()
.map(|path| format!("{}/{}", root_dir.to_str().unwrap(), path))
.collect::<Vec<_>>();
println!("included {include_dirs:?}");
let interface = interface
.iter()
.map(|path| format!("{}/{}", root_dir.to_str().unwrap(), path))
.collect::<Vec<_>>();
println!("interface {interface:?}");
let out_dir = root_dir.join(out_dir);
println!("outdir {out_dir:?}");
tonic_build::configure()
.build_client(build_client)
.build_server(build_server)
.build_transport(true)
.out_dir(out_dir.clone())
.file_descriptor_set_path(out_dir.clone().join("types.bin"))
.protoc_arg("--experimental_allow_proto3_optional")
.compile_protos(&include_dirs, &interface)
.expect("Failed to compile protos");
}

View File

@ -26,7 +26,7 @@ option go_package = "github.com/dapr/dapr/pkg/proto/common/v1;common";
// when Dapr runtime delivers HTTP content. // when Dapr runtime delivers HTTP content.
// //
// For example, when callers calls http invoke api // For example, when callers calls http invoke api
// POST http://localhost:3500/v1.0/invoke/<app_id>/method/<method>?query1=value1&query2=value2 // `POST http://localhost:3500/v1.0/invoke/<app_id>/method/<method>?query1=value1&query2=value2`
// //
// Dapr runtime will parse POST as a verb and extract querystring to quersytring map. // Dapr runtime will parse POST as a verb and extract querystring to quersytring map.
message HTTPExtension { message HTTPExtension {

View File

@ -151,25 +151,39 @@ service Dapr {
rpc SubtleVerifyAlpha1(SubtleVerifyRequest) returns (SubtleVerifyResponse); rpc SubtleVerifyAlpha1(SubtleVerifyRequest) returns (SubtleVerifyResponse);
// Starts a new instance of a workflow // Starts a new instance of a workflow
rpc StartWorkflowAlpha1 (StartWorkflowRequest) returns (StartWorkflowResponse) {} rpc StartWorkflowAlpha1 (StartWorkflowRequest) returns (StartWorkflowResponse) {
option deprecated = true;
}
// Gets details about a started workflow instance // Gets details about a started workflow instance
rpc GetWorkflowAlpha1 (GetWorkflowRequest) returns (GetWorkflowResponse) {} rpc GetWorkflowAlpha1 (GetWorkflowRequest) returns (GetWorkflowResponse) {
option deprecated = true;
}
// Purge Workflow // Purge Workflow
rpc PurgeWorkflowAlpha1 (PurgeWorkflowRequest) returns (google.protobuf.Empty) {} rpc PurgeWorkflowAlpha1 (PurgeWorkflowRequest) returns (google.protobuf.Empty) {
option deprecated = true;
}
// Terminates a running workflow instance // Terminates a running workflow instance
rpc TerminateWorkflowAlpha1 (TerminateWorkflowRequest) returns (google.protobuf.Empty) {} rpc TerminateWorkflowAlpha1 (TerminateWorkflowRequest) returns (google.protobuf.Empty) {
option deprecated = true;
}
// Pauses a running workflow instance // Pauses a running workflow instance
rpc PauseWorkflowAlpha1 (PauseWorkflowRequest) returns (google.protobuf.Empty) {} rpc PauseWorkflowAlpha1 (PauseWorkflowRequest) returns (google.protobuf.Empty) {
option deprecated = true;
}
// Resumes a paused workflow instance // Resumes a paused workflow instance
rpc ResumeWorkflowAlpha1 (ResumeWorkflowRequest) returns (google.protobuf.Empty) {} rpc ResumeWorkflowAlpha1 (ResumeWorkflowRequest) returns (google.protobuf.Empty) {
option deprecated = true;
}
// Raise an event to a running workflow instance // Raise an event to a running workflow instance
rpc RaiseEventWorkflowAlpha1 (RaiseEventWorkflowRequest) returns (google.protobuf.Empty) {} rpc RaiseEventWorkflowAlpha1 (RaiseEventWorkflowRequest) returns (google.protobuf.Empty) {
option deprecated = true;
}
// Starts a new instance of a workflow // Starts a new instance of a workflow
rpc StartWorkflowBeta1 (StartWorkflowRequest) returns (StartWorkflowResponse) {} rpc StartWorkflowBeta1 (StartWorkflowRequest) returns (StartWorkflowResponse) {}
@ -191,6 +205,7 @@ service Dapr {
// Raise an event to a running workflow instance // Raise an event to a running workflow instance
rpc RaiseEventWorkflowBeta1 (RaiseEventWorkflowRequest) returns (google.protobuf.Empty) {} rpc RaiseEventWorkflowBeta1 (RaiseEventWorkflowRequest) returns (google.protobuf.Empty) {}
// Shutdown the sidecar // Shutdown the sidecar
rpc Shutdown (ShutdownRequest) returns (google.protobuf.Empty) {} rpc Shutdown (ShutdownRequest) returns (google.protobuf.Empty) {}
@ -202,6 +217,9 @@ service Dapr {
// Delete a job // Delete a job
rpc DeleteJobAlpha1(DeleteJobRequest) returns (DeleteJobResponse) {} rpc DeleteJobAlpha1(DeleteJobRequest) returns (DeleteJobResponse) {}
// Converse with a LLM service
rpc ConverseAlpha1(ConversationRequest) returns (ConversationResponse) {}
} }
// InvokeServiceRequest represents the request message for Service invocation. // InvokeServiceRequest represents the request message for Service invocation.
@ -493,6 +511,7 @@ message InvokeBindingRequest {
// //
// Common metadata property: // Common metadata property:
// - ttlInSeconds : the time to live in seconds for the message. // - ttlInSeconds : the time to live in seconds for the message.
//
// If set in the binding definition will cause all messages to // If set in the binding definition will cause all messages to
// have a default time to live. The message ttl overrides any value // have a default time to live. The message ttl overrides any value
// in the binding definition. // in the binding definition.
@ -675,7 +694,14 @@ message GetMetadataResponse {
string runtime_version = 8 [json_name = "runtimeVersion"]; string runtime_version = 8 [json_name = "runtimeVersion"];
repeated string enabled_features = 9 [json_name = "enabledFeatures"]; repeated string enabled_features = 9 [json_name = "enabledFeatures"];
ActorRuntime actor_runtime = 10 [json_name = "actorRuntime"]; ActorRuntime actor_runtime = 10 [json_name = "actorRuntime"];
//TODO: Cassie: probably add scheduler runtime status optional MetadataScheduler scheduler = 11 [json_name = "scheduler"];
}
// MetadataScheduler is a message that contains the list of addresses of the
// scheduler connections.
message MetadataScheduler {
// connected_addresses the list of addresses of the scheduler connections.
repeated string connected_addresses = 1;
} }
message ActorRuntime { message ActorRuntime {
@ -1205,7 +1231,7 @@ message Job {
// //
// Systemd timer style cron accepts 6 fields: // Systemd timer style cron accepts 6 fields:
// seconds | minutes | hours | day of month | month | day of week // seconds | minutes | hours | day of month | month | day of week
// 0-59 | 0-59 | 0-23 | 1-31 | 1-12/jan-dec | 0-7/sun-sat // 0-59 | 0-59 | 0-23 | 1-31 | 1-12/jan-dec | 0-6/sun-sat
// //
// "0 30 * * * *" - every hour on the half hour // "0 30 * * * *" - every hour on the half hour
// "0 15 3 * * *" - every day at 03:15 // "0 15 3 * * *" - every day at 03:15
@ -1213,7 +1239,7 @@ message Job {
// Period string expressions: // Period string expressions:
// Entry | Description | Equivalent To // Entry | Description | Equivalent To
// ----- | ----------- | ------------- // ----- | ----------- | -------------
// @every <duration> | Run every <duration> (e.g. '@every 1h30m') | N/A // @every `<duration>` | Run every `<duration>` (e.g. '@every 1h30m') | N/A
// @yearly (or @annually) | Run once a year, midnight, Jan. 1st | 0 0 0 1 1 * // @yearly (or @annually) | Run once a year, midnight, Jan. 1st | 0 0 0 1 1 *
// @monthly | Run once a month, midnight, first of month | 0 0 0 1 * * // @monthly | Run once a month, midnight, first of month | 0 0 0 1 * *
// @weekly | Run once a week, midnight on Sunday | 0 0 0 * * 0 // @weekly | Run once a week, midnight on Sunday | 0 0 0 * * 0
@ -1274,3 +1300,55 @@ message DeleteJobRequest {
message DeleteJobResponse { message DeleteJobResponse {
// Empty // Empty
} }
// ConversationRequest is the request object for Conversation.
message ConversationRequest {
// The name of Conversation component
string name = 1;
// The ID of an existing chat (like in ChatGPT)
optional string contextID = 2;
// Inputs for the conversation, support multiple input in one time.
repeated ConversationInput inputs = 3;
// Parameters for all custom fields.
map<string, google.protobuf.Any> parameters = 4;
// The metadata passing to conversation components.
map<string, string> metadata = 5;
// Scrub PII data that comes back from the LLM
optional bool scrubPII = 6;
// Temperature for the LLM to optimize for creativity or predictability
optional double temperature = 7;
}
message ConversationInput {
// The content to send to the llm
string content = 1;
// The role to set for the message
optional string role = 2;
// Scrub PII data that goes into the LLM
optional bool scrubPII = 3;
}
// ConversationResult is the result for one input.
message ConversationResult {
// Result for the one conversation input.
string result = 1;
// Parameters for all custom fields.
map<string, google.protobuf.Any> parameters = 2;
}
// ConversationResponse is the response for Conversation.
message ConversationResponse {
// The ID of an existing chat (like in ChatGPT)
optional string contextID = 1;
// An array of results.
repeated ConversationResult outputs = 2;
}

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