Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/qrcode.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: qrcode

on:
push:
branches:
- master
pull_request:
paths:
- rust/qrcode/**
- .github/workflows/qrcode.yml

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
rust-qrcode:
runs-on: ubuntu-24.04
container: ghcr.io/dfinity/icp-dev-env-rust:1.0.0
env:
ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Deploy and test
working-directory: rust/qrcode
run: |
icp network start -d
icp deploy
make test
20 changes: 0 additions & 20 deletions rust/qrcode/.devcontainer/devcontainer.json

This file was deleted.

10 changes: 2 additions & 8 deletions rust/qrcode/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,12 @@
.DS_Store
**/.DS_Store

# dfx temporary files
.dfx/

# generated files
src/declarations/
# generated bindings
**/src/bindings/

# rust
target/

# frontend code
node_modules/
dist/

# environment variables
.env
113 changes: 0 additions & 113 deletions rust/qrcode/BUILD.md

This file was deleted.

4 changes: 2 additions & 2 deletions rust/qrcode/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion rust/qrcode/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[workspace]
members = ["src/qrcode_backend"]
members = ["backend"]
resolver = "2"
68 changes: 40 additions & 28 deletions rust/qrcode/Makefile
Original file line number Diff line number Diff line change
@@ -1,32 +1,44 @@
.PHONY: all
all: deploy
.PHONY: test

.PHONY: node_modules
.SILENT: node_modules
node_modules:
npm install
test:
@echo "=== Test 1: qrcode_query without logo or gradient ==="
@result=$$(icp canister call --query backend qrcode_query '("test", record {add_logo=false; add_gradient=false; add_transparency=null})') && \
echo "$$result" && \
echo "$$result" | grep -q 'Image = blob' && \
echo "PASS" || (echo "FAIL" && exit 1)

.PHONY: deploy
.SILENT: deploy
deploy: node_modules
dfx deploy
@echo "=== Test 2: qrcode_query with logo, no gradient ==="
@result=$$(icp canister call --query backend qrcode_query '("test", record {add_logo=true; add_gradient=false; add_transparency=null})') && \
echo "$$result" && \
echo "$$result" | grep -q 'Image = blob' && \
echo "PASS" || (echo "FAIL" && exit 1)

.PHONY: test
.SILENT: test
test: deploy
# Wait at least 2 seconds.
sleep 2
# Validate the image is generated as a query.
dfx canister call qrcode_backend qrcode_query '("test", record {add_gradient=false; add_logo=false})' | fgrep -q 'Image = blob' && echo PASS
dfx canister call qrcode_backend qrcode_query '("test", record {add_gradient=false; add_logo=true})' | fgrep -q 'Image = blob' && echo PASS
dfx canister call qrcode_backend qrcode_query '("test", record {add_gradient=true; add_logo=false})' | fgrep -q 'Image = blob' && echo PASS
dfx canister call qrcode_backend qrcode_query '("test", record {add_gradient=true; add_logo=true})' | fgrep -q 'Image = blob' && echo PASS
dfx canister call qrcode_backend qrcode_query '("test", record {add_gradient=true; add_logo=true; add_trasparency=opt true})' | fgrep -q 'Image = blob' && echo PASS
dfx canister call qrcode_backend qrcode_query '("test", record {add_gradient=true; add_logo=true; add_trasparency=opt false})' | fgrep -q 'Image = blob' && echo PASS
# Validate the image is generated as an update call.
dfx canister call qrcode_backend qrcode '("test", record {add_gradient=true; add_logo=true})' | fgrep -q 'Image = blob' && echo PASS
@echo "=== Test 3: qrcode_query with gradient, no logo ==="
@result=$$(icp canister call --query backend qrcode_query '("test", record {add_logo=false; add_gradient=true; add_transparency=null})') && \
echo "$$result" && \
echo "$$result" | grep -q 'Image = blob' && \
echo "PASS" || (echo "FAIL" && exit 1)

@echo "=== Test 4: qrcode_query with logo and gradient ==="
@result=$$(icp canister call --query backend qrcode_query '("test", record {add_logo=true; add_gradient=true; add_transparency=null})') && \
echo "$$result" && \
echo "$$result" | grep -q 'Image = blob' && \
echo "PASS" || (echo "FAIL" && exit 1)

@echo "=== Test 5: qrcode_query with transparency enabled ==="
@result=$$(icp canister call --query backend qrcode_query '("test", record {add_logo=true; add_gradient=true; add_transparency=opt true})') && \
echo "$$result" && \
echo "$$result" | grep -q 'Image = blob' && \
echo "PASS" || (echo "FAIL" && exit 1)

@echo "=== Test 6: qrcode_query with transparency disabled ==="
@result=$$(icp canister call --query backend qrcode_query '("test", record {add_logo=true; add_gradient=true; add_transparency=opt false})') && \
echo "$$result" && \
echo "$$result" | grep -q 'Image = blob' && \
echo "PASS" || (echo "FAIL" && exit 1)

.PHONY: clean
.SILENT: clean
clean:
rm -fr .dfx
@echo "=== Test 7: qrcode update call (waits for consensus) ==="
@result=$$(icp canister call backend qrcode '("test", record {add_logo=true; add_gradient=true; add_transparency=null})') && \
echo "$$result" && \
echo "$$result" | grep -q 'Image = blob' && \
echo "PASS" || (echo "FAIL" && exit 1)
73 changes: 27 additions & 46 deletions rust/qrcode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,74 +4,55 @@ This example shows that an Internet Computer dapp can perform a long-running com
This is possible due to a unique feature called Deterministic Time Slicing (DTS), which automatically divides long computations into smaller slices executed across multiple blocks.
Developers can write long-running code as usual and don't require anything special to take advantage of DTS, as demonstrated in this example.

You try the live version of the dapp running on the mainnet here: [https://khpe2-4qaaa-aaaao-a2fnq-cai.icp0.io/](https://khpe2-4qaaa-aaaao-a2fnq-cai.icp0.io/).
You can try the live version of the dapp running on the mainnet here: [https://khpe2-4qaaa-aaaao-a2fnq-cai.icp0.io/](https://khpe2-4qaaa-aaaao-a2fnq-cai.icp0.io/).

## Deploying from ICP Ninja
## How it works

The frontend consists of an HTML page with a form where users can enter text for the QR code and choose various options.
When the user clicks the "Generate!" button, a JavaScript handler initiates a call to the backend canister.

When viewing this project in ICP Ninja, you can deploy it directly to the mainnet for free by clicking "Run" in the upper right corner. Open this project in ICP Ninja:
The backend, written in Rust, uses the `qrcode-generator` and `image` crates to create a QR code from user text.
It also performs some image processing to add the Internet Computer logo and a color gradient to the final result.
Note that the amount of computational work may be significant for large images.

[![](https://icp.ninja/assets/open.svg)](https://icp.ninja/i?g=https://github.com/dfinity/examples/rust/qrcode)
For educational purposes, the backend offers two public endpoints for QR code generation: one for updates and another for queries.
Currently, DTS is supported for updates, but not for queries.
As a result, the update endpoint has a larger instruction limit compared to the query endpoint and thus can handle larger images.

## Build and deploy from the command-line
This example requires an installation of:
## Build and deploy from the command line

- [x] Install the [IC SDK](https://internetcomputer.org/docs/current/developer-docs/getting-started/install).
- [x] Make sure your Rust version is up-to-date (e.g., run `rustup update`).
- [x] Add the `wasm32` target to your rust installation (by running `rustup target add wasm32-unknown-unknown`).
- [x] Install `node.js` dependencies by running `npm install`.
- [x] Clone the example dapp project: `git clone https://github.com/dfinity/examples`
### Prerequisites

## Running locally
- Node.js
- icp-cli: `npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm`
- Rust with the `wasm32-unknown-unknown` target: `rustup target add wasm32-unknown-unknown`

Navigate into the folder containing the project's files and start a local instance of the replica with the command:
### Install

```sh
```bash
git clone https://github.com/dfinity/examples
cd examples/rust/qrcode
dfx start --clean --background
```

You can omit the `--background` argument if you want to see log messages of the dapp.

Now you can build and deploy the dapp with a single command:
### Deploy and test

```bash
dfx deploy
icp network start -d
icp deploy
make test
icp network stop
```

If you see any error, it might be worthwhile to consult the [developer forum](https://forum.dfinity.org/).
In case of successful deployment, you will see an output with local URLs:
If you want to interact with the frontend during development, run the Vite dev server for hot reload:

```bash
Deployed canisters.
URLs:
Frontend canister via browser
qrcode_frontend: ...
Backend canister via Candid interface:
qrcode_backend: ...
npm run dev --prefix frontend
```

Navigate to the frontend URL in your browser and you'll be able to interact with the dapp.

![Screenshot of the frontend UI](screenshot.png)


## How it works

The initial code of the dapp was autogenerated by `dfx` using the standard frontend/backend template.

The frontend consists of an HTML page with a form where users can enter text for the QR code and choose various options.
When the user clicks the "Generate!" button, a JavaScript handler initiates a call to the backend canister.
The heavy lifting of this call is managed by `candid`, `js-agent`, and `dfx`, which automatically generates a JavaScript object from the backend's Candid interface.
That object contains `async` functions for each of the backend's endpoints, and the button handler uses them to make the calls.

The backend, written in Rust, uses the `qrcode-generator` and `image` crates to create a QR code from user text.
It also performs some image processing, to add the Internet Computer logo and a color gradient to the final result.
Note the amount of computational work may be significant for large images.

For educational purposes, the backend offers two public endpoints for QR code generation: one for updates and another for queries.
Currently, DTS is supported for updates, but not for queries.
As a result, the update endpoint has a larger instruction limit compared to the query endpoint and thus can handle larger images.

## Security considerations and best practices

If you base your application on this example, it is recommended that you familiarize yourself with and adhere to the [security best practices](https://internetcomputer.org/docs/building-apps/security/overview) for developing on ICP. This example may not implement all the best practices.
If you base your application on this example, it is recommended that you familiarize yourself with and adhere to the [security best practices](https://docs.internetcomputer.org/guides/security/overview) for developing on ICP. This example may not implement all the best practices.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "backend"
version = "0.1.0"
edition = "2021"
name = "qrcode_backend"
version = "1.1.0"

[lib]
crate-type = ["cdylib"]
Expand Down
Loading
Loading