mirror of
https://github.com/XRPLF/clio.git
synced 2026-01-18 05:35:24 +00:00
Compare commits
16 Commits
2.6.0-rc2
...
experiment
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7eaf0005e4 | ||
|
|
497721ee7c | ||
|
|
26530108e3 | ||
|
|
fc88abdaeb | ||
|
|
8bc36c2c0b | ||
|
|
4e9558f76b | ||
|
|
84db880ce7 | ||
|
|
f88ce31363 | ||
|
|
e03f5e46c0 | ||
|
|
30da8d8f63 | ||
|
|
8f6bec2e25 | ||
|
|
0d9a83fd4d | ||
|
|
47c2af0421 | ||
|
|
c3e04426d3 | ||
|
|
d598396445 | ||
|
|
bbd2884e3b |
8
.github/workflows/build.yml
vendored
8
.github/workflows/build.yml
vendored
@@ -62,8 +62,6 @@ jobs:
|
||||
container: ${{ matrix.container }}
|
||||
conan_profile: ${{ matrix.conan_profile }}
|
||||
build_type: ${{ matrix.build_type }}
|
||||
download_ccache: true
|
||||
upload_ccache: true
|
||||
static: ${{ matrix.static }}
|
||||
run_unit_tests: true
|
||||
run_integration_tests: false
|
||||
@@ -78,8 +76,7 @@ jobs:
|
||||
container: '{ "image": "ghcr.io/xrplf/clio-ci:384e79cd32f5f6c0ab9be3a1122ead41c5a7e67d" }'
|
||||
conan_profile: gcc
|
||||
build_type: Debug
|
||||
download_ccache: true
|
||||
upload_ccache: false
|
||||
disable_cache: false
|
||||
code_coverage: true
|
||||
static: true
|
||||
upload_clio_server: false
|
||||
@@ -97,8 +94,7 @@ jobs:
|
||||
container: '{ "image": "ghcr.io/xrplf/clio-ci:384e79cd32f5f6c0ab9be3a1122ead41c5a7e67d" }'
|
||||
conan_profile: gcc
|
||||
build_type: Release
|
||||
download_ccache: true
|
||||
upload_ccache: false
|
||||
disable_cache: false
|
||||
code_coverage: false
|
||||
static: true
|
||||
upload_clio_server: false
|
||||
|
||||
13
.github/workflows/build_and_test.yml
vendored
13
.github/workflows/build_and_test.yml
vendored
@@ -23,14 +23,8 @@ on:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
download_ccache:
|
||||
description: Whether to download ccache from the cache
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
upload_ccache:
|
||||
description: Whether to upload ccache to the cache
|
||||
disable_cache:
|
||||
description: Whether ccache should be disabled
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
@@ -83,8 +77,7 @@ jobs:
|
||||
container: ${{ inputs.container }}
|
||||
conan_profile: ${{ inputs.conan_profile }}
|
||||
build_type: ${{ inputs.build_type }}
|
||||
download_ccache: ${{ inputs.download_ccache }}
|
||||
upload_ccache: ${{ inputs.upload_ccache }}
|
||||
disable_cache: ${{ inputs.disable_cache }}
|
||||
code_coverage: false
|
||||
static: ${{ inputs.static }}
|
||||
upload_clio_server: ${{ inputs.upload_clio_server }}
|
||||
|
||||
25
.github/workflows/build_impl.yml
vendored
25
.github/workflows/build_impl.yml
vendored
@@ -23,17 +23,10 @@ on:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
download_ccache:
|
||||
description: Whether to download ccache from the cache
|
||||
disable_cache:
|
||||
description: Whether ccache should be disabled
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
upload_ccache:
|
||||
description: Whether to upload ccache to the cache
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
code_coverage:
|
||||
description: Whether to enable code coverage
|
||||
@@ -97,15 +90,15 @@ jobs:
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/.github/actions/prepare-runner@7951b682e5a2973b28b0719a72f01fc4b0d0c34f
|
||||
with:
|
||||
disable_ccache: ${{ !inputs.download_ccache }}
|
||||
disable_ccache: ${{ inputs.disable_cache }}
|
||||
|
||||
- name: Setup conan on macOS
|
||||
if: ${{ runner.os == 'macOS' }}
|
||||
if: runner.os == 'macOS'
|
||||
shell: bash
|
||||
run: ./.github/scripts/conan/init.sh
|
||||
|
||||
- name: Restore cache
|
||||
if: ${{ inputs.download_ccache }}
|
||||
if: ${{ !inputs.disable_cache }}
|
||||
uses: ./.github/actions/restore_cache
|
||||
id: restore_cache
|
||||
with:
|
||||
@@ -151,7 +144,7 @@ jobs:
|
||||
path: build_time_report.txt
|
||||
|
||||
- name: Show ccache's statistics
|
||||
if: ${{ inputs.download_ccache }}
|
||||
if: ${{ !inputs.disable_cache }}
|
||||
shell: bash
|
||||
id: ccache_stats
|
||||
run: |
|
||||
@@ -169,7 +162,7 @@ jobs:
|
||||
run: strip build/clio_integration_tests
|
||||
|
||||
- name: Upload clio_server
|
||||
if: ${{ inputs.upload_clio_server && !inputs.code_coverage && !inputs.analyze_build_time }}
|
||||
if: inputs.upload_clio_server && !inputs.code_coverage && !inputs.analyze_build_time
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: clio_server_${{ runner.os }}_${{ inputs.build_type }}_${{ inputs.conan_profile }}
|
||||
@@ -190,14 +183,14 @@ jobs:
|
||||
path: build/clio_integration_tests
|
||||
|
||||
- name: Upload Clio Linux package
|
||||
if: ${{ inputs.package }}
|
||||
if: inputs.package
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: clio_deb_package_${{ runner.os }}_${{ inputs.build_type }}_${{ inputs.conan_profile }}
|
||||
path: build/*.deb
|
||||
|
||||
- name: Save cache
|
||||
if: ${{ inputs.upload_ccache && github.ref == 'refs/heads/develop' }}
|
||||
if: ${{ !inputs.disable_cache && github.ref == 'refs/heads/develop' }}
|
||||
uses: ./.github/actions/save_cache
|
||||
with:
|
||||
conan_profile: ${{ inputs.conan_profile }}
|
||||
|
||||
3
.github/workflows/clang-tidy.yml
vendored
3
.github/workflows/clang-tidy.yml
vendored
@@ -1,8 +1,6 @@
|
||||
name: Clang-tidy check
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [develop]
|
||||
schedule:
|
||||
- cron: "0 9 * * 1-5"
|
||||
workflow_dispatch:
|
||||
@@ -24,7 +22,6 @@ env:
|
||||
|
||||
jobs:
|
||||
clang_tidy:
|
||||
if: github.event_name != 'push' || contains(github.event.head_commit.message, 'clang-tidy auto fixes')
|
||||
runs-on: heavy
|
||||
container:
|
||||
image: ghcr.io/xrplf/clio-ci:384e79cd32f5f6c0ab9be3a1122ead41c5a7e67d
|
||||
|
||||
30
.github/workflows/clang-tidy_on_fix_merged.yml
vendored
Normal file
30
.github/workflows/clang-tidy_on_fix_merged.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: Restart clang-tidy workflow
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [develop]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
restart_clang_tidy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
actions: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Check last commit matches clang-tidy auto fixes
|
||||
id: check
|
||||
shell: bash
|
||||
run: |
|
||||
passed=$(if [[ "$(git log -1 --pretty=format:%s | grep 'style: clang-tidy auto fixes')" ]]; then echo 'true' ; else echo 'false' ; fi)
|
||||
echo "passed=\"$passed\"" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Run clang-tidy workflow
|
||||
if: ${{ contains(steps.check.outputs.passed, 'true') }}
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
GH_REPO: ${{ github.repository }}
|
||||
run: gh workflow run clang-tidy.yml
|
||||
6
.github/workflows/nightly.yml
vendored
6
.github/workflows/nightly.yml
vendored
@@ -61,8 +61,7 @@ jobs:
|
||||
run_unit_tests: true
|
||||
run_integration_tests: true
|
||||
upload_clio_server: true
|
||||
download_ccache: false
|
||||
upload_ccache: false
|
||||
disable_cache: true
|
||||
|
||||
analyze_build_time:
|
||||
name: Analyze Build Time
|
||||
@@ -85,8 +84,7 @@ jobs:
|
||||
container: ${{ matrix.container }}
|
||||
conan_profile: ${{ matrix.conan_profile }}
|
||||
build_type: Release
|
||||
download_ccache: false
|
||||
upload_ccache: false
|
||||
disable_cache: true
|
||||
code_coverage: false
|
||||
static: ${{ matrix.static }}
|
||||
upload_clio_server: false
|
||||
|
||||
3
.github/workflows/release.yml
vendored
3
.github/workflows/release.yml
vendored
@@ -41,8 +41,7 @@ jobs:
|
||||
run_unit_tests: true
|
||||
run_integration_tests: true
|
||||
upload_clio_server: true
|
||||
download_ccache: false
|
||||
upload_ccache: false
|
||||
disable_cache: true
|
||||
expected_version: ${{ github.event_name == 'push' && github.ref_name || '' }}
|
||||
|
||||
release:
|
||||
|
||||
3
.github/workflows/sanitizers.yml
vendored
3
.github/workflows/sanitizers.yml
vendored
@@ -45,8 +45,7 @@ jobs:
|
||||
with:
|
||||
runs_on: heavy
|
||||
container: '{ "image": "ghcr.io/xrplf/clio-ci:384e79cd32f5f6c0ab9be3a1122ead41c5a7e67d" }'
|
||||
download_ccache: false
|
||||
upload_ccache: false
|
||||
disable_cache: true
|
||||
conan_profile: ${{ matrix.compiler }}${{ matrix.sanitizer_ext }}
|
||||
build_type: ${{ matrix.build_type }}
|
||||
static: false
|
||||
|
||||
16
.github/workflows/test_impl.yml
vendored
16
.github/workflows/test_impl.yml
vendored
@@ -39,11 +39,11 @@ jobs:
|
||||
runs-on: ${{ inputs.runs_on }}
|
||||
container: ${{ inputs.container != '' && fromJson(inputs.container) || null }}
|
||||
|
||||
if: ${{ inputs.run_unit_tests }}
|
||||
if: inputs.run_unit_tests
|
||||
|
||||
env:
|
||||
# TODO: remove completely when we have fixed all currently existing issues with sanitizers
|
||||
SANITIZER_IGNORE_ERRORS: ${{ endsWith(inputs.conan_profile, '.tsan') || inputs.conan_profile == 'clang.asan' || (inputs.conan_profile == 'gcc.asan' && inputs.build_type == 'Release') }}
|
||||
SANITIZER_IGNORE_ERRORS: ${{ endsWith(inputs.conan_profile, '.asan') || endsWith(inputs.conan_profile, '.tsan') }}
|
||||
|
||||
steps:
|
||||
- name: Cleanup workspace
|
||||
@@ -63,15 +63,15 @@ jobs:
|
||||
run: chmod +x ./clio_tests
|
||||
|
||||
- name: Run clio_tests (regular)
|
||||
if: ${{ env.SANITIZER_IGNORE_ERRORS == 'false' }}
|
||||
if: env.SANITIZER_IGNORE_ERRORS == 'false'
|
||||
run: ./clio_tests
|
||||
|
||||
- name: Run clio_tests (sanitizer errors ignored)
|
||||
if: ${{ env.SANITIZER_IGNORE_ERRORS == 'true' }}
|
||||
if: env.SANITIZER_IGNORE_ERRORS == 'true'
|
||||
run: ./.github/scripts/execute-tests-under-sanitizer ./clio_tests
|
||||
|
||||
- name: Check for sanitizer report
|
||||
if: ${{ env.SANITIZER_IGNORE_ERRORS == 'true' }}
|
||||
if: env.SANITIZER_IGNORE_ERRORS == 'true'
|
||||
shell: bash
|
||||
id: check_report
|
||||
run: |
|
||||
@@ -82,7 +82,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Upload sanitizer report
|
||||
if: ${{ env.SANITIZER_IGNORE_ERRORS == 'true' && steps.check_report.outputs.found_report == 'true' }}
|
||||
if: env.SANITIZER_IGNORE_ERRORS == 'true' && steps.check_report.outputs.found_report == 'true'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sanitizer_report_${{ runner.os }}_${{ inputs.build_type }}_${{ inputs.conan_profile }}
|
||||
@@ -90,7 +90,7 @@ jobs:
|
||||
include-hidden-files: true
|
||||
|
||||
- name: Create an issue
|
||||
if: ${{ false && env.SANITIZER_IGNORE_ERRORS == 'true' && steps.check_report.outputs.found_report == 'true' }}
|
||||
if: false && env.SANITIZER_IGNORE_ERRORS == 'true' && steps.check_report.outputs.found_report == 'true'
|
||||
uses: ./.github/actions/create_issue
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
@@ -108,7 +108,7 @@ jobs:
|
||||
runs-on: ${{ inputs.runs_on }}
|
||||
container: ${{ inputs.container != '' && fromJson(inputs.container) || null }}
|
||||
|
||||
if: ${{ inputs.run_integration_tests }}
|
||||
if: inputs.run_integration_tests
|
||||
|
||||
services:
|
||||
scylladb:
|
||||
|
||||
20
.github/workflows/update_docker_ci.yml
vendored
20
.github/workflows/update_docker_ci.yml
vendored
@@ -61,7 +61,7 @@ jobs:
|
||||
files: "docker/compilers/gcc/**"
|
||||
|
||||
- uses: ./.github/actions/build_docker_image
|
||||
if: ${{ steps.changed-files.outputs.any_changed == 'true' }}
|
||||
if: steps.changed-files.outputs.any_changed == 'true'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }}
|
||||
@@ -99,7 +99,7 @@ jobs:
|
||||
files: "docker/compilers/gcc/**"
|
||||
|
||||
- uses: ./.github/actions/build_docker_image
|
||||
if: ${{ steps.changed-files.outputs.any_changed == 'true' }}
|
||||
if: steps.changed-files.outputs.any_changed == 'true'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }}
|
||||
@@ -140,7 +140,7 @@ jobs:
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
@@ -148,14 +148,14 @@ jobs:
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to DockerHub
|
||||
if: ${{ github.repository_owner == 'XRPLF' && github.event_name != 'pull_request' }}
|
||||
if: github.repository_owner == 'XRPLF' && github.event_name != 'pull_request'
|
||||
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USER }}
|
||||
password: ${{ secrets.DOCKERHUB_PW }}
|
||||
|
||||
- name: Create and push multi-arch manifest
|
||||
if: ${{ github.event_name != 'pull_request' && steps.changed-files.outputs.any_changed == 'true' }}
|
||||
if: github.event_name != 'pull_request' && steps.changed-files.outputs.any_changed == 'true'
|
||||
run: |
|
||||
push_image() {
|
||||
image=$1
|
||||
@@ -188,7 +188,7 @@ jobs:
|
||||
files: "docker/compilers/clang/**"
|
||||
|
||||
- uses: ./.github/actions/build_docker_image
|
||||
if: ${{ steps.changed-files.outputs.any_changed == 'true' }}
|
||||
if: steps.changed-files.outputs.any_changed == 'true'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }}
|
||||
@@ -224,7 +224,7 @@ jobs:
|
||||
files: "docker/tools/**"
|
||||
|
||||
- uses: ./.github/actions/build_docker_image
|
||||
if: ${{ steps.changed-files.outputs.any_changed == 'true' }}
|
||||
if: steps.changed-files.outputs.any_changed == 'true'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
@@ -255,7 +255,7 @@ jobs:
|
||||
files: "docker/tools/**"
|
||||
|
||||
- uses: ./.github/actions/build_docker_image
|
||||
if: ${{ steps.changed-files.outputs.any_changed == 'true' }}
|
||||
if: steps.changed-files.outputs.any_changed == 'true'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
@@ -289,7 +289,7 @@ jobs:
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
@@ -297,7 +297,7 @@ jobs:
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create and push multi-arch manifest
|
||||
if: ${{ github.event_name != 'pull_request' && steps.changed-files.outputs.any_changed == 'true' }}
|
||||
if: github.event_name != 'pull_request' && steps.changed-files.outputs.any_changed == 'true'
|
||||
run: |
|
||||
image=${{ needs.repo.outputs.GHCR_REPO }}/clio-tools
|
||||
docker buildx imagetools create \
|
||||
|
||||
6
.github/workflows/upload_conan_deps.yml
vendored
6
.github/workflows/upload_conan_deps.yml
vendored
@@ -77,7 +77,7 @@ jobs:
|
||||
disable_ccache: true
|
||||
|
||||
- name: Setup conan on macOS
|
||||
if: ${{ runner.os == 'macOS' }}
|
||||
if: runner.os == 'macOS'
|
||||
shell: bash
|
||||
run: ./.github/scripts/conan/init.sh
|
||||
|
||||
@@ -94,9 +94,9 @@ jobs:
|
||||
build_type: ${{ matrix.build_type }}
|
||||
|
||||
- name: Login to Conan
|
||||
if: ${{ github.repository_owner == 'XRPLF' && github.event_name != 'pull_request' }}
|
||||
if: github.repository_owner == 'XRPLF' && github.event_name != 'pull_request'
|
||||
run: conan remote login -p ${{ secrets.CONAN_PASSWORD }} xrplf ${{ secrets.CONAN_USERNAME }}
|
||||
|
||||
- name: Upload Conan packages
|
||||
if: ${{ github.repository_owner == 'XRPLF' && github.event_name != 'pull_request' && github.event_name != 'schedule' }}
|
||||
if: github.repository_owner == 'XRPLF' && github.event_name != 'pull_request' && github.event_name != 'schedule'
|
||||
run: conan upload "*" -r=xrplf --confirm ${{ github.event.inputs.force_upload == 'true' && '--force' || '' }}
|
||||
|
||||
@@ -37,13 +37,13 @@ repos:
|
||||
exclude: LICENSE.md
|
||||
|
||||
- repo: https://github.com/hadolint/hadolint
|
||||
rev: 4e697ba704fd23b2409b947a319c19c3ee54d24f # frozen: v2.14.0
|
||||
rev: c3dc18df7a501f02a560a2cc7ba3c69a85ca01d3 # frozen: v2.13.1-beta
|
||||
hooks:
|
||||
- id: hadolint-docker
|
||||
# hadolint-docker is a special hook that runs hadolint in a Docker container
|
||||
# Docker is not installed in the environment where pre-commit is run
|
||||
stages: [manual]
|
||||
entry: hadolint/hadolint:v2.14 hadolint
|
||||
entry: hadolint/hadolint:v2.12.1-beta hadolint
|
||||
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: 63c8f8312b7559622c0d82815639671ae42132ac # frozen: v2.4.1
|
||||
@@ -80,7 +80,7 @@ repos:
|
||||
language: script
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: 719856d56a62953b8d2839fb9e851f25c3cfeef8 # frozen: v21.1.2
|
||||
rev: 86fdcc9bd34d6afbbd29358b97436c8ffe3aa3b2 # frozen: v21.1.0
|
||||
hooks:
|
||||
- id: clang-format
|
||||
args: [--style=file]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"requires": [
|
||||
"zlib/1.3.1#b8bc2603263cf7eccbd6e17e66b0ed76%1756234269.497",
|
||||
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1756234289.683",
|
||||
"xrpl/2.6.1#973af2bf9631f239941dd9f5a100bb84%1759275059.342",
|
||||
"xrpl/2.6.0#57b93b5a6c99dc8511fccb3bb5390352%1756820296.642",
|
||||
"sqlite3/3.49.1#8631739a4c9b93bd3d6b753bac548a63%1756234266.869",
|
||||
"spdlog/1.15.3#3ca0e9e6b83af4d0151e26541d140c86%1754401846.61",
|
||||
"soci/4.0.3#a9f8d773cd33e356b5879a4b0564f287%1756234262.318",
|
||||
@@ -41,12 +41,15 @@
|
||||
"overrides": {
|
||||
"boost/1.83.0": [
|
||||
null,
|
||||
"boost/1.83.0#5d975011d65b51abb2d2f6eb8386b368"
|
||||
"boost/1.83.0"
|
||||
],
|
||||
"protobuf/3.21.12": [
|
||||
null,
|
||||
"protobuf/3.21.12"
|
||||
],
|
||||
"boost/1.86.0": [
|
||||
"boost/1.83.0#5d975011d65b51abb2d2f6eb8386b368"
|
||||
],
|
||||
"lz4/1.9.4": [
|
||||
"lz4/1.10.0"
|
||||
],
|
||||
@@ -55,4 +58,4 @@
|
||||
]
|
||||
},
|
||||
"config_requires": []
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ class ClioConan(ConanFile):
|
||||
'protobuf/3.21.12',
|
||||
'grpc/1.50.1',
|
||||
'openssl/1.1.1w',
|
||||
'xrpl/2.6.1',
|
||||
'xrpl/2.6.0',
|
||||
'zlib/1.3.1',
|
||||
'libbacktrace/cci.20210118',
|
||||
'spdlog/1.15.3',
|
||||
|
||||
@@ -3,8 +3,6 @@ PROJECT_LOGO = ${SOURCE}/docs/img/xrpl-logo.svg
|
||||
PROJECT_NUMBER = ${DOC_CLIO_VERSION}
|
||||
PROJECT_BRIEF = The XRP Ledger API server.
|
||||
|
||||
DOT_GRAPH_MAX_NODES = 100
|
||||
|
||||
EXTRACT_ALL = NO
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_PACKAGE = YES
|
||||
@@ -34,18 +32,12 @@ SORT_MEMBERS_CTORS_1ST = YES
|
||||
GENERATE_TREEVIEW = YES
|
||||
DISABLE_INDEX = NO
|
||||
FULL_SIDEBAR = NO
|
||||
HTML_HEADER = ${SOURCE}/docs/doxygen-awesome-theme/doxygen-custom/header.html
|
||||
HTML_HEADER = ${SOURCE}/docs/doxygen-awesome-theme/header.html
|
||||
HTML_EXTRA_STYLESHEET = ${SOURCE}/docs/doxygen-awesome-theme/doxygen-awesome.css \
|
||||
${SOURCE}/docs/doxygen-awesome-theme/doxygen-awesome-sidebar-only.css \
|
||||
${SOURCE}/docs/doxygen-awesome-theme/doxygen-awesome-sidebar-only-darkmode-toggle.css \
|
||||
${SOURCE}/docs/doxygen-awesome-theme/doxygen-custom/custom.css \
|
||||
${SOURCE}/docs/doxygen-awesome-theme/doxygen-custom/theme-robot.css \
|
||||
${SOURCE}/docs/doxygen-awesome-theme/doxygen-custom/theme-round.css \
|
||||
${SOURCE}/docs/github-corner-disable.css
|
||||
${SOURCE}/docs/doxygen-awesome-theme/doxygen-awesome-sidebar-only-darkmode-toggle.css
|
||||
HTML_EXTRA_FILES = ${SOURCE}/docs/doxygen-awesome-theme/doxygen-awesome-darkmode-toggle.js \
|
||||
${SOURCE}/docs/doxygen-awesome-theme/doxygen-awesome-fragment-copy-button.js \
|
||||
${SOURCE}/docs/doxygen-awesome-theme/doxygen-awesome-interactive-toc.js \
|
||||
${SOURCE}/docs/doxygen-awesome-theme/doxygen-custom/toggle-alternative-theme.js
|
||||
${SOURCE}/docs/doxygen-awesome-theme/doxygen-awesome-interactive-toc.js
|
||||
|
||||
HTML_COLORSTYLE = LIGHT
|
||||
HTML_COLORSTYLE_HUE = 209
|
||||
|
||||
@@ -1,10 +1,29 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/**
|
||||
|
||||
Doxygen Awesome
|
||||
https://github.com/jothepro/doxygen-awesome-css
|
||||
|
||||
Copyright (c) 2021 - 2025 jothepro
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 - 2023 jothepro
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/**
|
||||
|
||||
Doxygen Awesome
|
||||
https://github.com/jothepro/doxygen-awesome-css
|
||||
|
||||
Copyright (c) 2022 - 2025 jothepro
|
||||
|
||||
*/
|
||||
|
||||
class DoxygenAwesomeFragmentCopyButton extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.onclick=this.copyContent
|
||||
}
|
||||
static title = "Copy to clipboard"
|
||||
static copyIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M23.04,10.322c0,-2.582 -2.096,-4.678 -4.678,-4.678l-6.918,-0c-2.582,-0 -4.678,2.096 -4.678,4.678c0,-0 0,8.04 0,8.04c0,2.582 2.096,4.678 4.678,4.678c0,-0 6.918,-0 6.918,-0c2.582,-0 4.678,-2.096 4.678,-4.678c0,-0 0,-8.04 0,-8.04Zm-2.438,-0l-0,8.04c-0,1.236 -1.004,2.24 -2.24,2.24l-6.918,-0c-1.236,-0 -2.239,-1.004 -2.239,-2.24l-0,-8.04c-0,-1.236 1.003,-2.24 2.239,-2.24c0,0 6.918,0 6.918,0c1.236,0 2.24,1.004 2.24,2.24Z"/><path d="M5.327,16.748c-0,0.358 -0.291,0.648 -0.649,0.648c0,0 0,0 0,0c-2.582,0 -4.678,-2.096 -4.678,-4.678c0,0 0,-8.04 0,-8.04c0,-2.582 2.096,-4.678 4.678,-4.678l6.918,0c2.168,0 3.994,1.478 4.523,3.481c0.038,0.149 0.005,0.306 -0.09,0.428c-0.094,0.121 -0.239,0.191 -0.392,0.191c-0.451,0.005 -1.057,0.005 -1.457,0.005c-0.238,0 -0.455,-0.14 -0.553,-0.357c-0.348,-0.773 -1.128,-1.31 -2.031,-1.31c-0,0 -6.918,0 -6.918,0c-1.236,0 -2.24,1.004 -2.24,2.24l0,8.04c0,1.236 1.004,2.24 2.24,2.24l0,-0c0.358,-0 0.649,0.29 0.649,0.648c-0,0.353 -0,0.789 -0,1.142Z" style="fill-opacity:0.6;"/></svg>`
|
||||
static successIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M8.084,16.111c-0.09,0.09 -0.212,0.141 -0.34,0.141c-0.127,-0 -0.249,-0.051 -0.339,-0.141c-0.746,-0.746 -2.538,-2.538 -3.525,-3.525c-0.375,-0.375 -0.983,-0.375 -1.357,0c-0.178,0.178 -0.369,0.369 -0.547,0.547c-0.375,0.375 -0.375,0.982 -0,1.357c1.135,1.135 3.422,3.422 4.75,4.751c0.27,0.27 0.637,0.421 1.018,0.421c0.382,0 0.749,-0.151 1.019,-0.421c2.731,-2.732 10.166,-10.167 12.454,-12.455c0.375,-0.375 0.375,-0.982 -0,-1.357c-0.178,-0.178 -0.369,-0.369 -0.547,-0.547c-0.375,-0.375 -0.982,-0.375 -1.357,0c-2.273,2.273 -9.567,9.567 -11.229,11.229Z"/></svg>`
|
||||
static successDuration = 980
|
||||
static init() {
|
||||
$(function() {
|
||||
$(document).ready(function() {
|
||||
if(navigator.clipboard) {
|
||||
const fragments = document.getElementsByClassName("fragment")
|
||||
for(const fragment of fragments) {
|
||||
const fragmentWrapper = document.createElement("div")
|
||||
fragmentWrapper.className = "doxygen-awesome-fragment-wrapper"
|
||||
const fragmentCopyButton = document.createElement("doxygen-awesome-fragment-copy-button")
|
||||
fragmentCopyButton.innerHTML = DoxygenAwesomeFragmentCopyButton.copyIcon
|
||||
fragmentCopyButton.title = DoxygenAwesomeFragmentCopyButton.title
|
||||
|
||||
fragment.parentNode.replaceChild(fragmentWrapper, fragment)
|
||||
fragmentWrapper.appendChild(fragment)
|
||||
fragmentWrapper.appendChild(fragmentCopyButton)
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
copyContent() {
|
||||
const content = this.previousSibling.cloneNode(true)
|
||||
// filter out line number from file listings
|
||||
content.querySelectorAll(".lineno, .ttc").forEach((node) => {
|
||||
node.remove()
|
||||
})
|
||||
let textContent = content.textContent
|
||||
// remove trailing newlines that appear in file listings
|
||||
let numberOfTrailingNewlines = 0
|
||||
while(textContent.charAt(textContent.length - (numberOfTrailingNewlines + 1)) == '\n') {
|
||||
numberOfTrailingNewlines++;
|
||||
}
|
||||
textContent = textContent.substring(0, textContent.length - numberOfTrailingNewlines)
|
||||
navigator.clipboard.writeText(textContent);
|
||||
this.classList.add("success")
|
||||
this.innerHTML = DoxygenAwesomeFragmentCopyButton.successIcon
|
||||
window.setTimeout(() => {
|
||||
this.classList.remove("success")
|
||||
this.innerHTML = DoxygenAwesomeFragmentCopyButton.copyIcon
|
||||
}, DoxygenAwesomeFragmentCopyButton.successDuration);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("doxygen-awesome-fragment-copy-button", DoxygenAwesomeFragmentCopyButton)
|
||||
@@ -1,10 +1,29 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/**
|
||||
|
||||
Doxygen Awesome
|
||||
https://github.com/jothepro/doxygen-awesome-css
|
||||
|
||||
Copyright (c) 2022 - 2025 jothepro
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 - 2023 jothepro
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
@@ -36,7 +55,9 @@ class DoxygenAwesomeInteractiveToc {
|
||||
headerNode: document.getElementById(id)
|
||||
})
|
||||
|
||||
document.getElementById("doc-content")?.addEventListener("scroll",this.throttle(DoxygenAwesomeInteractiveToc.update, 100))
|
||||
document.getElementById("doc-content")?.addEventListener("scroll", () => {
|
||||
DoxygenAwesomeInteractiveToc.update()
|
||||
})
|
||||
})
|
||||
DoxygenAwesomeInteractiveToc.update()
|
||||
}
|
||||
@@ -57,16 +78,4 @@ class DoxygenAwesomeInteractiveToc {
|
||||
active?.classList.add("active")
|
||||
active?.classList.remove("aboveActive")
|
||||
}
|
||||
|
||||
static throttle(func, delay) {
|
||||
let lastCall = 0;
|
||||
return function (...args) {
|
||||
const now = new Date().getTime();
|
||||
if (now - lastCall < delay) {
|
||||
return;
|
||||
}
|
||||
lastCall = now;
|
||||
return setTimeout(() => {func(...args)}, delay);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,30 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
/**
|
||||
|
||||
Doxygen Awesome
|
||||
https://github.com/jothepro/doxygen-awesome-css
|
||||
|
||||
Copyright (c) 2021 - 2025 jothepro
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 - 2023 jothepro
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,10 +1,29 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/**
|
||||
|
||||
Doxygen Awesome
|
||||
https://github.com/jothepro/doxygen-awesome-css
|
||||
|
||||
Copyright (c) 2021 - 2025 jothepro
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 - 2023 jothepro
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
@@ -41,6 +60,10 @@ html {
|
||||
height: calc(100vh - var(--top-height)) !important;
|
||||
}
|
||||
|
||||
#nav-tree {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#top {
|
||||
display: block;
|
||||
border-bottom: none;
|
||||
@@ -50,24 +73,22 @@ html {
|
||||
overflow: hidden;
|
||||
background: var(--side-nav-background);
|
||||
}
|
||||
|
||||
#main-nav {
|
||||
float: left;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.ui-resizable-handle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ui-resizable-e {
|
||||
width: 0;
|
||||
cursor: default;
|
||||
width: 1px !important;
|
||||
background: var(--separator-color);
|
||||
box-shadow: 0 calc(-2 * var(--top-height)) 0 0 var(--separator-color);
|
||||
}
|
||||
|
||||
#nav-path {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
left: calc(var(--side-nav-fixed-width) + 1px);
|
||||
left: var(--side-nav-fixed-width);
|
||||
bottom: 0;
|
||||
width: auto;
|
||||
}
|
||||
@@ -92,14 +113,4 @@ html {
|
||||
left: var(--spacing-medium) !important;
|
||||
right: auto;
|
||||
}
|
||||
|
||||
#nav-sync {
|
||||
bottom: 4px;
|
||||
right: auto;
|
||||
left: 300px;
|
||||
width: 35px;
|
||||
top: auto !important;
|
||||
user-select: none;
|
||||
position: fixed
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,29 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/**
|
||||
|
||||
Doxygen Awesome
|
||||
https://github.com/jothepro/doxygen-awesome-css
|
||||
|
||||
Copyright (c) 2021 - 2025 jothepro
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 - 2023 jothepro
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
@@ -13,9 +32,6 @@ html {
|
||||
--primary-color: #1779c4;
|
||||
--primary-dark-color: #335c80;
|
||||
--primary-light-color: #70b1e9;
|
||||
--on-primary-color: #ffffff;
|
||||
|
||||
--link-color: var(--primary-color);
|
||||
|
||||
/* page base colors */
|
||||
--page-background-color: #ffffff;
|
||||
@@ -26,15 +42,14 @@ html {
|
||||
--separator-color: #dedede;
|
||||
|
||||
/* border radius for all rounded components. Will affect many components, like dropdowns, memitems, codeblocks, ... */
|
||||
--border-radius-large: 10px;
|
||||
--border-radius-small: 5px;
|
||||
--border-radius-medium: 8px;
|
||||
--border-radius-large: 8px;
|
||||
--border-radius-small: 4px;
|
||||
--border-radius-medium: 6px;
|
||||
|
||||
/* default spacings. Most components reference these values for spacing, to provide uniform spacing on the page. */
|
||||
--spacing-small: 5px;
|
||||
--spacing-medium: 10px;
|
||||
--spacing-large: 16px;
|
||||
--spacing-xlarge: 20px;
|
||||
|
||||
/* default box shadow used for raising an element above the normal content. Used in dropdowns, search result, ... */
|
||||
--box-shadow: 0 2px 8px 0 rgba(0,0,0,.075);
|
||||
@@ -98,7 +113,7 @@ html {
|
||||
*/
|
||||
--menu-display: block;
|
||||
|
||||
--menu-focus-foreground: var(--on-primary-color);
|
||||
--menu-focus-foreground: var(--page-background-color);
|
||||
--menu-focus-background: var(--primary-color);
|
||||
--menu-selected-background: rgba(0,0,0,.05);
|
||||
|
||||
@@ -295,11 +310,10 @@ body {
|
||||
font-size: var(--page-font-size);
|
||||
}
|
||||
|
||||
body, table, div, p, dl, #nav-tree .label, #nav-tree a, .title,
|
||||
body, table, div, p, dl, #nav-tree .label, .title,
|
||||
.sm-dox a, .sm-dox a:hover, .sm-dox a:focus, #projectname,
|
||||
.SelectItem, #MSearchField, .navpath li.navelem a,
|
||||
.navpath li.navelem a:hover, p.reference, p.definition, div.toc li, div.toc h3,
|
||||
#page-nav ul.page-outline li a {
|
||||
.navpath li.navelem a:hover, p.reference, p.definition, div.toc li, div.toc h3 {
|
||||
font-family: var(--font-family);
|
||||
}
|
||||
|
||||
@@ -318,13 +332,8 @@ p.reference, p.definition {
|
||||
}
|
||||
|
||||
a:link, a:visited, a:hover, a:focus, a:active {
|
||||
color: var(--link-color) !important;
|
||||
color: var(--primary-color) !important;
|
||||
font-weight: 500;
|
||||
background: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a.anchor {
|
||||
@@ -339,8 +348,6 @@ a.anchor {
|
||||
#top {
|
||||
background: var(--header-background);
|
||||
border-bottom: 1px solid var(--separator-color);
|
||||
position: relative;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
@@ -355,7 +362,6 @@ a.anchor {
|
||||
#main-nav {
|
||||
flex-grow: 5;
|
||||
padding: var(--spacing-small) var(--spacing-medium);
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
#titlearea {
|
||||
@@ -435,36 +441,19 @@ a.anchor {
|
||||
}
|
||||
|
||||
.sm-dox a span.sub-arrow {
|
||||
top: 15px;
|
||||
right: 10px;
|
||||
box-sizing: content-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: inline-block;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
transform: rotate(45deg);
|
||||
border-width: 0;
|
||||
border-right: 2px solid var(--header-foreground);
|
||||
border-bottom: 2px solid var(--header-foreground);
|
||||
background: none;
|
||||
border-color: var(--header-foreground) transparent transparent transparent;
|
||||
}
|
||||
|
||||
.sm-dox a:hover span.sub-arrow {
|
||||
border-color: var(--menu-focus-foreground);
|
||||
background: none;
|
||||
border-color: var(--menu-focus-foreground) transparent transparent transparent;
|
||||
}
|
||||
|
||||
.sm-dox ul a span.sub-arrow {
|
||||
transform: rotate(-45deg);
|
||||
border-width: 0;
|
||||
border-right: 2px solid var(--header-foreground);
|
||||
border-bottom: 2px solid var(--header-foreground);
|
||||
border-color: transparent transparent transparent var(--page-foreground-color);
|
||||
}
|
||||
|
||||
.sm-dox ul a:hover span.sub-arrow {
|
||||
border-color: var(--menu-focus-foreground);
|
||||
background: none;
|
||||
border-color: transparent transparent transparent var(--menu-focus-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -491,7 +480,7 @@ a.anchor {
|
||||
|
||||
.sm-dox ul a {
|
||||
color: var(--page-foreground-color) !important;
|
||||
background: none;
|
||||
background: var(--page-background-color);
|
||||
font-size: var(--navigation-font-size);
|
||||
}
|
||||
|
||||
@@ -563,13 +552,6 @@ a.anchor {
|
||||
box-shadow: none;
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.sm-dox li {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* until Doxygen 1.9.4 */
|
||||
@@ -591,17 +573,6 @@ a.anchor {
|
||||
padding-left: 0
|
||||
}
|
||||
|
||||
/* Doxygen 1.14.0 */
|
||||
.search-icon::before {
|
||||
background: none;
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
.search-icon::after {
|
||||
background: none;
|
||||
top: 12px;
|
||||
}
|
||||
|
||||
.SelectionMark {
|
||||
user-select: none;
|
||||
}
|
||||
@@ -805,15 +776,12 @@ html.dark-mode iframe#MSearchResults {
|
||||
*/
|
||||
|
||||
#side-nav {
|
||||
padding: 0 !important;
|
||||
background: var(--side-nav-background);
|
||||
min-width: 8px;
|
||||
max-width: 50vw;
|
||||
}
|
||||
|
||||
|
||||
#nav-tree, #top {
|
||||
border-right: 1px solid var(--separator-color);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
#side-nav {
|
||||
display: none;
|
||||
@@ -822,95 +790,34 @@ html.dark-mode iframe#MSearchResults {
|
||||
#doc-content {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
#top {
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
|
||||
#nav-tree {
|
||||
background: var(--side-nav-background);
|
||||
margin-right: -1px;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
margin-right: 1px;
|
||||
}
|
||||
|
||||
#nav-tree .label {
|
||||
font-size: var(--navigation-font-size);
|
||||
line-height: var(--tree-item-height);
|
||||
}
|
||||
|
||||
#nav-tree span.label a:hover {
|
||||
background: none;
|
||||
}
|
||||
|
||||
#nav-tree .item {
|
||||
height: var(--tree-item-height);
|
||||
line-height: var(--tree-item-height);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#nav-tree-contents {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#main-menu > li:last-child {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#nav-tree .item > a:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#nav-sync {
|
||||
bottom: var(--spacing-medium);
|
||||
right: var(--spacing-medium) !important;
|
||||
bottom: 12px;
|
||||
right: 12px;
|
||||
top: auto !important;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
div.nav-sync-icon {
|
||||
border: 1px solid var(--separator-color);
|
||||
border-radius: var(--border-radius-medium);
|
||||
background: var(--page-background-color);
|
||||
width: 30px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
div.nav-sync-icon:hover {
|
||||
background: var(--page-background-color);
|
||||
}
|
||||
|
||||
span.sync-icon-left, div.nav-sync-icon:hover span.sync-icon-left {
|
||||
border-left: 2px solid var(--primary-color);
|
||||
border-top: 2px solid var(--primary-color);
|
||||
top: 5px;
|
||||
left: 6px;
|
||||
}
|
||||
span.sync-icon-right, div.nav-sync-icon:hover span.sync-icon-right {
|
||||
border-right: 2px solid var(--primary-color);
|
||||
border-bottom: 2px solid var(--primary-color);
|
||||
top: 5px;
|
||||
left: initial;
|
||||
right: 6px;
|
||||
}
|
||||
|
||||
div.nav-sync-icon.active::after, div.nav-sync-icon.active:hover::after {
|
||||
border-top: 2px solid var(--primary-color);
|
||||
top: 9px;
|
||||
left: 6px;
|
||||
width: 19px;
|
||||
}
|
||||
|
||||
#nav-tree .selected {
|
||||
text-shadow: none;
|
||||
background-image: none;
|
||||
background-color: transparent;
|
||||
position: relative;
|
||||
color: var(--primary-color) !important;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
#nav-tree .selected::after {
|
||||
@@ -936,27 +843,9 @@ div.nav-sync-icon.active::after, div.nav-sync-icon.active:hover::after {
|
||||
|
||||
#nav-tree .arrow {
|
||||
opacity: var(--side-nav-arrow-opacity);
|
||||
background: none;
|
||||
}
|
||||
|
||||
#nav-tree span.arrowhead {
|
||||
margin: 0 0 1px 2px;
|
||||
}
|
||||
|
||||
span.arrowhead {
|
||||
border-color: var(--primary-light-color);
|
||||
}
|
||||
|
||||
.selected span.arrowhead {
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
|
||||
#nav-tree ul li:first-child > div > a {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.contents .arrow {
|
||||
.arrow {
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
font-size: 45%;
|
||||
@@ -964,7 +853,7 @@ span.arrowhead {
|
||||
margin-right: 2px;
|
||||
font-family: serif;
|
||||
height: auto;
|
||||
padding-bottom: 4px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#nav-tree div.item:hover .arrow, #nav-tree a:focus .arrow {
|
||||
@@ -978,11 +867,9 @@ span.arrowhead {
|
||||
}
|
||||
|
||||
.ui-resizable-e {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.ui-resizable-e:hover {
|
||||
background: var(--separator-color);
|
||||
width: 4px;
|
||||
background: transparent;
|
||||
box-shadow: inset -1px 0 0 0 var(--separator-color);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -991,7 +878,7 @@ span.arrowhead {
|
||||
|
||||
div.header {
|
||||
border-bottom: 1px solid var(--separator-color);
|
||||
background: none;
|
||||
background-color: var(--page-background-color);
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
@@ -1030,7 +917,7 @@ div.headertitle {
|
||||
div.header .title {
|
||||
font-weight: 600;
|
||||
font-size: 225%;
|
||||
padding: var(--spacing-medium) var(--spacing-xlarge);
|
||||
padding: var(--spacing-medium) var(--spacing-large);
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
@@ -1047,10 +934,9 @@ td.memSeparator {
|
||||
|
||||
span.mlabel {
|
||||
background: var(--primary-color);
|
||||
color: var(--on-primary-color);
|
||||
border: none;
|
||||
padding: 4px 9px;
|
||||
border-radius: var(--border-radius-large);
|
||||
border-radius: 12px;
|
||||
margin-right: var(--spacing-medium);
|
||||
}
|
||||
|
||||
@@ -1059,7 +945,7 @@ span.mlabel:last-of-type {
|
||||
}
|
||||
|
||||
div.contents {
|
||||
padding: 0 var(--spacing-xlarge);
|
||||
padding: 0 var(--spacing-large);
|
||||
}
|
||||
|
||||
div.contents p, div.contents li {
|
||||
@@ -1070,16 +956,6 @@ div.contents div.dyncontent {
|
||||
margin: var(--spacing-medium) 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
div.contents {
|
||||
padding: 0 var(--spacing-large);
|
||||
}
|
||||
|
||||
div.header .title {
|
||||
padding: var(--spacing-medium) var(--spacing-large);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html:not(.light-mode) div.contents div.dyncontent img,
|
||||
html:not(.light-mode) div.contents center img,
|
||||
@@ -1103,7 +979,7 @@ html.dark-mode div.contents .dotgraph iframe
|
||||
filter: brightness(89%) hue-rotate(180deg) invert();
|
||||
}
|
||||
|
||||
td h2.groupheader, h2.groupheader {
|
||||
h2.groupheader {
|
||||
border-bottom: 0px;
|
||||
color: var(--page-foreground-color);
|
||||
box-shadow:
|
||||
@@ -1164,7 +1040,7 @@ blockquote::after {
|
||||
blockquote p {
|
||||
margin: var(--spacing-small) 0 var(--spacing-medium) 0;
|
||||
}
|
||||
.paramname, .paramname em {
|
||||
.paramname {
|
||||
font-weight: 600;
|
||||
color: var(--primary-dark-color);
|
||||
}
|
||||
@@ -1214,7 +1090,7 @@ div.contents .toc {
|
||||
border: 0;
|
||||
border-left: 1px solid var(--separator-color);
|
||||
border-radius: 0;
|
||||
background-color: var(--page-background-color);
|
||||
background-color: transparent;
|
||||
box-shadow: none;
|
||||
position: sticky;
|
||||
top: var(--toc-sticky-top);
|
||||
@@ -1322,115 +1198,24 @@ div.toc li a.aboveActive {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Page Outline (Doxygen >= 1.14.0)
|
||||
*/
|
||||
|
||||
#page-nav {
|
||||
background: var(--page-background-color);
|
||||
border-left: 1px solid var(--separator-color);
|
||||
}
|
||||
|
||||
#page-nav #page-nav-resize-handle {
|
||||
background: var(--separator-color);
|
||||
}
|
||||
|
||||
#page-nav #page-nav-resize-handle::after {
|
||||
border-left: 1px solid var(--primary-color);
|
||||
border-right: 1px solid var(--primary-color);
|
||||
}
|
||||
|
||||
#page-nav #page-nav-tree #page-nav-contents {
|
||||
top: var(--spacing-large);
|
||||
}
|
||||
|
||||
#page-nav ul.page-outline {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#page-nav ul.page-outline li a {
|
||||
font-size: var(--toc-font-size) !important;
|
||||
color: var(--page-secondary-foreground-color) !important;
|
||||
display: inline-block;
|
||||
line-height: calc(2 * var(--toc-font-size));
|
||||
}
|
||||
|
||||
#page-nav ul.page-outline li a a.anchorlink {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#page-nav ul.page-outline li.vis ~ * a {
|
||||
color: var(--page-foreground-color) !important;
|
||||
}
|
||||
|
||||
#page-nav ul.page-outline li.vis:not(.vis ~ .vis) a, #page-nav ul.page-outline li a:hover {
|
||||
color: var(--primary-color) !important;
|
||||
}
|
||||
|
||||
#page-nav ul.page-outline .vis {
|
||||
background: var(--page-background-color);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#page-nav ul.page-outline .vis::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 4px;
|
||||
background: var(--page-secondary-foreground-color);
|
||||
}
|
||||
|
||||
#page-nav ul.page-outline .vis:not(.vis ~ .vis)::after {
|
||||
top: 1px;
|
||||
border-top-right-radius: var(--border-radius-small);
|
||||
}
|
||||
|
||||
#page-nav ul.page-outline .vis:not(:has(~ .vis))::after {
|
||||
bottom: 1px;
|
||||
border-bottom-right-radius: var(--border-radius-small);
|
||||
}
|
||||
|
||||
|
||||
#page-nav ul.page-outline .arrow {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#page-nav ul.page-outline .arrow span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
#container {
|
||||
grid-template-columns: initial !important;
|
||||
}
|
||||
|
||||
#page-nav {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Code & Fragments
|
||||
*/
|
||||
|
||||
code, div.fragment, pre.fragment, span.tt {
|
||||
code, div.fragment, pre.fragment {
|
||||
border-radius: var(--border-radius-small);
|
||||
border: 1px solid var(--separator-color);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
code, span.tt {
|
||||
code {
|
||||
display: inline;
|
||||
background: var(--code-background);
|
||||
color: var(--code-foreground);
|
||||
padding: 2px 6px;
|
||||
border-radius: var(--border-radius-small);
|
||||
}
|
||||
|
||||
div.fragment, pre.fragment {
|
||||
border-radius: var(--border-radius-medium);
|
||||
margin: var(--spacing-medium) 0;
|
||||
padding: calc(var(--spacing-large) - (var(--spacing-large) / 6)) var(--spacing-large);
|
||||
background: var(--fragment-background);
|
||||
@@ -1488,7 +1273,7 @@ div.fragment, pre.fragment {
|
||||
}
|
||||
}
|
||||
|
||||
code, code a, pre.fragment, div.fragment, div.fragment .line, div.fragment span, div.fragment .line a, div.fragment .line span, span.tt {
|
||||
code, code a, pre.fragment, div.fragment, div.fragment .line, div.fragment span, div.fragment .line a, div.fragment .line span {
|
||||
font-family: var(--font-family-monospace);
|
||||
font-size: var(--code-font-size) !important;
|
||||
}
|
||||
@@ -1562,10 +1347,6 @@ div.line.glow {
|
||||
dl warning, attention, note, deprecated, bug, ...
|
||||
*/
|
||||
|
||||
dl {
|
||||
line-height: calc(1.65 * var(--page-font-size));
|
||||
}
|
||||
|
||||
dl.bug dt a, dl.deprecated dt a, dl.todo dt a {
|
||||
font-weight: bold !important;
|
||||
}
|
||||
@@ -1731,7 +1512,6 @@ div.memitem {
|
||||
border-top-right-radius: var(--border-radius-medium);
|
||||
border-bottom-right-radius: var(--border-radius-medium);
|
||||
border-bottom-left-radius: var(--border-radius-medium);
|
||||
border-top-left-radius: 0;
|
||||
overflow: hidden;
|
||||
display: block !important;
|
||||
}
|
||||
@@ -1963,7 +1743,7 @@ table.fieldtable th {
|
||||
color: var(--tablehead-foreground);
|
||||
}
|
||||
|
||||
table.fieldtable td.fieldtype, .fieldtable td.fieldname, .fieldtable td.fieldinit, .fieldtable td.fielddoc, .fieldtable th {
|
||||
table.fieldtable td.fieldtype, .fieldtable td.fieldname, .fieldtable td.fielddoc, .fieldtable th {
|
||||
border-bottom: 1px solid var(--separator-color);
|
||||
border-right: 1px solid var(--separator-color);
|
||||
}
|
||||
@@ -1998,10 +1778,8 @@ table.memberdecls tr[class^='memitem'] .memTemplParams {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
table.memberdecls tr.heading + tr[class^='memitem'] td.memItemLeft,
|
||||
table.memberdecls tr.heading + tr[class^='memitem'] td.memItemRight,
|
||||
table.memberdecls td.memItemLeft,
|
||||
table.memberdecls td.memItemRight,
|
||||
table.memberdecls .memItemLeft,
|
||||
table.memberdecls .memItemRight,
|
||||
table.memberdecls .memTemplItemLeft,
|
||||
table.memberdecls .memTemplItemRight,
|
||||
table.memberdecls .memTemplParams {
|
||||
@@ -2013,34 +1791,8 @@ table.memberdecls .memTemplParams {
|
||||
background-color: var(--fragment-background);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
|
||||
tr.heading + tr[class^='memitem'] td.memItemRight, tr.groupHeader + tr[class^='memitem'] td.memItemRight, tr.inherit_header + tr[class^='memitem'] td.memItemRight {
|
||||
border-top-right-radius: var(--border-radius-small);
|
||||
}
|
||||
|
||||
table.memberdecls tr:last-child td.memItemRight, table.memberdecls tr:last-child td.mdescRight, table.memberdecls tr[class^='memitem']:has(+ tr.groupHeader) td.memItemRight, table.memberdecls tr[class^='memitem']:has(+ tr.inherit_header) td.memItemRight, table.memberdecls tr[class^='memdesc']:has(+ tr.groupHeader) td.mdescRight, table.memberdecls tr[class^='memdesc']:has(+ tr.inherit_header) td.mdescRight {
|
||||
border-bottom-right-radius: var(--border-radius-small);
|
||||
}
|
||||
|
||||
table.memberdecls tr:last-child td.memItemLeft, table.memberdecls tr:last-child td.mdescLeft, table.memberdecls tr[class^='memitem']:has(+ tr.groupHeader) td.memItemLeft, table.memberdecls tr[class^='memitem']:has(+ tr.inherit_header) td.memItemLeft, table.memberdecls tr[class^='memdesc']:has(+ tr.groupHeader) td.mdescLeft, table.memberdecls tr[class^='memdesc']:has(+ tr.inherit_header) td.mdescLeft {
|
||||
border-bottom-left-radius: var(--border-radius-small);
|
||||
}
|
||||
|
||||
tr.heading + tr[class^='memitem'] td.memItemLeft, tr.groupHeader + tr[class^='memitem'] td.memItemLeft, tr.inherit_header + tr[class^='memitem'] td.memItemLeft {
|
||||
border-top-left-radius: var(--border-radius-small);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
table.memname td.memname {
|
||||
font-size: var(--memname-font-size);
|
||||
}
|
||||
|
||||
table.memberdecls .memTemplItemLeft,
|
||||
table.memberdecls .template .memItemLeft,
|
||||
table.memberdecls .memTemplItemRight,
|
||||
table.memberdecls .template .memItemRight {
|
||||
table.memberdecls .memTemplItemRight {
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
@@ -2052,13 +1804,13 @@ table.memberdecls .memTemplParams {
|
||||
padding-bottom: var(--spacing-small);
|
||||
}
|
||||
|
||||
table.memberdecls .memTemplItemLeft, table.memberdecls .template .memItemLeft {
|
||||
table.memberdecls .memTemplItemLeft {
|
||||
border-radius: 0 0 0 var(--border-radius-small);
|
||||
border-left: 1px solid var(--separator-color);
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
table.memberdecls .memTemplItemRight, table.memberdecls .template .memItemRight {
|
||||
table.memberdecls .memTemplItemRight {
|
||||
border-radius: 0 0 var(--border-radius-small) 0;
|
||||
border-right: 1px solid var(--separator-color);
|
||||
padding-left: 0;
|
||||
@@ -2084,14 +1836,8 @@ table.memberdecls .mdescLeft, table.memberdecls .mdescRight {
|
||||
background: none;
|
||||
color: var(--page-foreground-color);
|
||||
padding: var(--spacing-small) 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
table.memberdecls [class^="memdesc"] {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
|
||||
table.memberdecls .memItemLeft,
|
||||
table.memberdecls .memTemplItemLeft {
|
||||
padding-right: var(--spacing-medium);
|
||||
@@ -2114,10 +1860,6 @@ table.memberdecls .inherit_header td {
|
||||
color: var(--page-secondary-foreground-color);
|
||||
}
|
||||
|
||||
table.memberdecls span.dynarrow {
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
table.memberdecls img[src="closed.png"],
|
||||
table.memberdecls img[src="open.png"],
|
||||
div.dynheader img[src="open.png"],
|
||||
@@ -2134,10 +1876,6 @@ div.dynheader img[src="closed.png"] {
|
||||
transition: transform var(--animation-duration) ease-out;
|
||||
}
|
||||
|
||||
tr.heading + tr[class^='memitem'] td.memItemLeft, tr.groupHeader + tr[class^='memitem'] td.memItemLeft, tr.inherit_header + tr[class^='memitem'] td.memItemLeft, tr.heading + tr[class^='memitem'] td.memItemRight, tr.groupHeader + tr[class^='memitem'] td.memItemRight, tr.inherit_header + tr[class^='memitem'] td.memItemRight {
|
||||
border-top: 1px solid var(--separator-color);
|
||||
}
|
||||
|
||||
table.memberdecls img {
|
||||
margin-right: 10px;
|
||||
}
|
||||
@@ -2162,10 +1900,7 @@ div.dynheader img[src="closed.png"] {
|
||||
table.memberdecls .mdescRight,
|
||||
table.memberdecls .memTemplItemLeft,
|
||||
table.memberdecls .memTemplItemRight,
|
||||
table.memberdecls .memTemplParams,
|
||||
table.memberdecls .template .memItemLeft,
|
||||
table.memberdecls .template .memItemRight,
|
||||
table.memberdecls .template .memParams {
|
||||
table.memberdecls .memTemplParams {
|
||||
display: block;
|
||||
text-align: left;
|
||||
padding-left: var(--spacing-large);
|
||||
@@ -2178,14 +1913,12 @@ div.dynheader img[src="closed.png"] {
|
||||
|
||||
table.memberdecls .memItemLeft,
|
||||
table.memberdecls .mdescLeft,
|
||||
table.memberdecls .memTemplItemLeft,
|
||||
table.memberdecls .template .memItemLeft {
|
||||
border-bottom: 0 !important;
|
||||
padding-bottom: 0 !important;
|
||||
table.memberdecls .memTemplItemLeft {
|
||||
border-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
table.memberdecls .memTemplItemLeft,
|
||||
table.memberdecls .template .memItemLeft {
|
||||
table.memberdecls .memTemplItemLeft {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
@@ -2195,12 +1928,10 @@ div.dynheader img[src="closed.png"] {
|
||||
|
||||
table.memberdecls .memItemRight,
|
||||
table.memberdecls .mdescRight,
|
||||
table.memberdecls .memTemplItemRight,
|
||||
table.memberdecls .template .memItemRight {
|
||||
border-top: 0 !important;
|
||||
padding-top: 0 !important;
|
||||
table.memberdecls .memTemplItemRight {
|
||||
border-top: 0;
|
||||
padding-top: 0;
|
||||
padding-right: var(--spacing-large);
|
||||
padding-bottom: var(--spacing-medium);
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
@@ -2235,22 +1966,6 @@ div.dynheader img[src="closed.png"] {
|
||||
max-height: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
tr.heading + tr[class^='memitem'] td.memItemRight, tr.groupHeader + tr[class^='memitem'] td.memItemRight, tr.inherit_header + tr[class^='memitem'] td.memItemRight {
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
table.memberdecls tr:last-child td.memItemRight, table.memberdecls tr:last-child td.mdescRight, table.memberdecls tr[class^='memitem']:has(+ tr.groupHeader) td.memItemRight, table.memberdecls tr[class^='memitem']:has(+ tr.inherit_header) td.memItemRight, table.memberdecls tr[class^='memdesc']:has(+ tr.groupHeader) td.mdescRight, table.memberdecls tr[class^='memdesc']:has(+ tr.inherit_header) td.mdescRight {
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
table.memberdecls tr:last-child td.memItemLeft, table.memberdecls tr:last-child td.mdescLeft, table.memberdecls tr[class^='memitem']:has(+ tr.groupHeader) td.memItemLeft, table.memberdecls tr[class^='memitem']:has(+ tr.inherit_header) td.memItemLeft, table.memberdecls tr[class^='memdesc']:has(+ tr.groupHeader) td.mdescLeft, table.memberdecls tr[class^='memdesc']:has(+ tr.inherit_header) td.mdescLeft {
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
tr.heading + tr[class^='memitem'] td.memItemLeft, tr.groupHeader + tr[class^='memitem'] td.memItemLeft, tr.inherit_header + tr[class^='memitem'] td.memItemLeft {
|
||||
border-top-left-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2267,16 +1982,14 @@ hr {
|
||||
}
|
||||
|
||||
.contents hr {
|
||||
box-shadow: 100px 0 var(--separator-color),
|
||||
-100px 0 var(--separator-color),
|
||||
500px 0 var(--separator-color),
|
||||
-500px 0 var(--separator-color),
|
||||
900px 0 var(--separator-color),
|
||||
-900px 0 var(--separator-color),
|
||||
1400px 0 var(--separator-color),
|
||||
-1400px 0 var(--separator-color),
|
||||
1900px 0 var(--separator-color),
|
||||
-1900px 0 var(--separator-color);
|
||||
box-shadow: 100px 0 0 var(--separator-color),
|
||||
-100px 0 0 var(--separator-color),
|
||||
500px 0 0 var(--separator-color),
|
||||
-500px 0 0 var(--separator-color),
|
||||
1500px 0 0 var(--separator-color),
|
||||
-1500px 0 0 var(--separator-color),
|
||||
2000px 0 0 var(--separator-color),
|
||||
-2000px 0 0 var(--separator-color);
|
||||
}
|
||||
|
||||
.contents img, .contents .center, .contents center, .contents div.image object {
|
||||
@@ -2439,7 +2152,9 @@ div.qindex {
|
||||
background: var(--page-background-color);
|
||||
border: none;
|
||||
border-top: 1px solid var(--separator-color);
|
||||
border-bottom: 1px solid var(--separator-color);
|
||||
border-bottom: 0;
|
||||
box-shadow: 0 0.75px 0 var(--separator-color);
|
||||
font-size: var(--navigation-font-size);
|
||||
}
|
||||
|
||||
@@ -2468,10 +2183,6 @@ address.footer {
|
||||
color: var(--primary-color) !important;
|
||||
}
|
||||
|
||||
.navpath li.navelem a:hover {
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.navpath li.navelem b {
|
||||
color: var(--primary-dark-color);
|
||||
font-weight: 500;
|
||||
@@ -2490,11 +2201,7 @@ li.navelem:first-child:before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#nav-path ul {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
#nav-path li.navelem:has(.el):after {
|
||||
#nav-path li.navelem:after {
|
||||
content: '';
|
||||
border: 5px solid var(--page-background-color);
|
||||
border-bottom-color: transparent;
|
||||
@@ -2505,21 +2212,7 @@ li.navelem:first-child:before {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
#nav-path li.navelem:not(:has(.el)):after {
|
||||
background: var(--page-background-color);
|
||||
box-shadow: 1px -1px 0 1px var(--separator-color);
|
||||
border-radius: 0 var(--border-radius-medium) 0 50px;
|
||||
}
|
||||
|
||||
#nav-path li.navelem:not(:has(.el)) {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
#nav-path li.navelem:not(:has(.el)):hover, #nav-path li.navelem:not(:has(.el)):hover:after {
|
||||
background-color: var(--separator-color);
|
||||
}
|
||||
|
||||
#nav-path li.navelem:has(.el):before {
|
||||
#nav-path li.navelem:before {
|
||||
content: '';
|
||||
border: 5px solid var(--separator-color);
|
||||
border-bottom-color: transparent;
|
||||
@@ -2645,7 +2338,7 @@ doxygen-awesome-dark-mode-toggle {
|
||||
height: var(--searchbar-height);
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: var(--searchbar-border-radius);
|
||||
border-radius: var(--searchbar-height);
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
line-height: var(--searchbar-height);
|
||||
@@ -2830,7 +2523,6 @@ h2:hover a.anchorlink, h1:hover a.anchorlink, h3:hover a.anchorlink, h4:hover a.
|
||||
float: left;
|
||||
white-space: nowrap;
|
||||
font-weight: normal;
|
||||
font-family: var(--font-family);
|
||||
padding: calc(var(--spacing-large) / 2) var(--spacing-large);
|
||||
border-radius: var(--border-radius-medium);
|
||||
transition: background-color var(--animation-duration) ease-in-out, font-weight var(--animation-duration) ease-in-out;
|
||||
@@ -2975,46 +2667,3 @@ h2:hover a.anchorlink, h1:hover a.anchorlink, h3:hover a.anchorlink, h4:hover a.
|
||||
border-radius: 0 var(--border-radius-medium) var(--border-radius-medium) 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Bordered image
|
||||
*/
|
||||
|
||||
html.dark-mode .darkmode_inverted_image img, /* < doxygen 1.9.3 */
|
||||
html.dark-mode .darkmode_inverted_image object[type="image/svg+xml"] /* doxygen 1.9.3 */ {
|
||||
filter: brightness(89%) hue-rotate(180deg) invert();
|
||||
}
|
||||
|
||||
.bordered_image {
|
||||
border-radius: var(--border-radius-small);
|
||||
border: 1px solid var(--separator-color);
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.bordered_image:empty {
|
||||
border: none;
|
||||
}
|
||||
|
||||
html.dark-mode .bordered_image img, /* < doxygen 1.9.3 */
|
||||
html.dark-mode .bordered_image object[type="image/svg+xml"] /* doxygen 1.9.3 */ {
|
||||
border-radius: var(--border-radius-small);
|
||||
}
|
||||
|
||||
/*
|
||||
Button
|
||||
*/
|
||||
|
||||
.primary-button {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
background: var(--primary-color);
|
||||
color: var(--page-background-color) !important;
|
||||
border-radius: var(--border-radius-medium);
|
||||
padding: var(--spacing-small) var(--spacing-medium);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.primary-button:hover {
|
||||
background: var(--primary-dark-color);
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
.github-corner svg {
|
||||
fill: var(--primary-light-color);
|
||||
color: var(--page-background-color);
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
.github-corner svg {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
#projectnumber {
|
||||
margin-right: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
.title_screenshot {
|
||||
filter: drop-shadow(0px 3px 10px rgba(0,0,0,0.22));
|
||||
max-width: 500px;
|
||||
margin: var(--spacing-large) 0;
|
||||
}
|
||||
|
||||
.title_screenshot .caption {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#theme-selection {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: var(--side-nav-background);
|
||||
padding: 5px 2px 5px 8px;
|
||||
box-shadow: 0 -4px 4px -2px var(--side-nav-background);
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#theme-selection label {
|
||||
border: 1px solid var(--separator-color);
|
||||
border-right: 0;
|
||||
color: var(--page-foreground-color);
|
||||
font-size: var(--toc-font-size);
|
||||
padding: 0 8px;
|
||||
display: inline-block;
|
||||
height: 22px;
|
||||
box-sizing: border-box;
|
||||
border-radius: var(--border-radius-medium) 0 0 var(--border-radius-medium);
|
||||
line-height: 20px;
|
||||
background: var(--page-background-color);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html:not(.light-mode) #theme-select {
|
||||
background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23aaaaaa'><polygon points='0,0 100,0 50,50'/></svg>") no-repeat;
|
||||
background-size: 8px;
|
||||
background-position: calc(100% - 6px) 65%;
|
||||
background-color: var(--page-background-color);
|
||||
}
|
||||
}
|
||||
|
||||
html.dark-mode #theme-select {
|
||||
background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23aaaaaa'><polygon points='0,0 100,0 50,50'/></svg>") no-repeat;
|
||||
background-size: 8px;
|
||||
background-position: calc(100% - 6px) 65%;
|
||||
background-color: var(--page-background-color);
|
||||
}
|
||||
|
||||
#theme-select {
|
||||
border: 1px solid var(--separator-color);
|
||||
border-radius: 0 var(--border-radius-medium) var(--border-radius-medium) 0;
|
||||
padding: 0;
|
||||
height: 22px;
|
||||
font-size: var(--toc-font-size);
|
||||
font-family: var(--font-family);
|
||||
width: 215px;
|
||||
color: var(--primary-color);
|
||||
border-left: 0;
|
||||
display: inline-block;
|
||||
opacity: 0.7;
|
||||
outline: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23888888'><polygon points='0,0 100,0 50,50'/></svg>") no-repeat;
|
||||
background-size: 8px;
|
||||
background-position: calc(100% - 6px) 65%;
|
||||
background-repeat: no-repeat;
|
||||
background-color: var(--page-background-color);
|
||||
}
|
||||
|
||||
#theme-selection:hover #theme-select, #theme-selection:hover label {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#nav-tree-contents {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
#theme-selection {
|
||||
box-shadow: none;
|
||||
background: none;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
#theme-select {
|
||||
width: 80px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#theme-selection label {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#nav-path ul li.navelem:first-child {
|
||||
margin-left: 160px;
|
||||
}
|
||||
|
||||
ul li.footer:not(:first-child) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#nav-path {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
background: var(--page-background-color);
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||
<meta name="generator" content="Doxygen $doxygenversion"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
|
||||
<!-- BEGIN opengraph metadata -->
|
||||
<meta property="og:title" content="Doxygen Awesome" />
|
||||
<meta property="og:image" content="https://repository-images.githubusercontent.com/348492097/4f16df80-88fb-11eb-9d31-4015ff22c452" />
|
||||
<meta property="og:description" content="Custom CSS theme for doxygen html-documentation with lots of customization parameters." />
|
||||
<meta property="og:url" content="https://jothepro.github.io/doxygen-awesome-css/" />
|
||||
<!-- END opengraph metadata -->
|
||||
|
||||
<!-- BEGIN twitter metadata -->
|
||||
<meta name="twitter:image:src" content="https://repository-images.githubusercontent.com/348492097/4f16df80-88fb-11eb-9d31-4015ff22c452" />
|
||||
<meta name="twitter:title" content="Doxygen Awesome" />
|
||||
<meta name="twitter:description" content="Custom CSS theme for doxygen html-documentation with lots of customization parameters." />
|
||||
<!-- END twitter metadata -->
|
||||
|
||||
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
|
||||
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
|
||||
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
|
||||
<link rel="icon" type="image/svg+xml" href="logo.drawio.svg"/>
|
||||
<script type="text/javascript" src="$relpath^jquery.js"></script>
|
||||
<script type="text/javascript" src="$relpath^dynsections.js"></script>
|
||||
<script type="text/javascript" src="$relpath^doxygen-awesome-darkmode-toggle.js"></script>
|
||||
<script type="text/javascript" src="$relpath^doxygen-awesome-fragment-copy-button.js"></script>
|
||||
<script type="text/javascript" src="$relpath^doxygen-awesome-paragraph-link.js"></script>
|
||||
<script type="text/javascript" src="$relpath^doxygen-awesome-interactive-toc.js"></script>
|
||||
<script type="text/javascript" src="$relpath^doxygen-awesome-tabs.js"></script>
|
||||
<script type="text/javascript" src="$relpath^toggle-alternative-theme.js"></script>
|
||||
<script type="text/javascript">
|
||||
DoxygenAwesomeFragmentCopyButton.init()
|
||||
DoxygenAwesomeDarkModeToggle.init()
|
||||
DoxygenAwesomeParagraphLink.init()
|
||||
DoxygenAwesomeInteractiveToc.init()
|
||||
DoxygenAwesomeTabs.init()
|
||||
</script>
|
||||
$treeview
|
||||
$search
|
||||
$mathjax
|
||||
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
|
||||
$extrastylesheet
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- https://tholman.com/github-corners/ -->
|
||||
<a href="https://github.com/jothepro/doxygen-awesome-css" class="github-corner" title="View source on GitHub" target="_blank" rel="noopener noreferrer">
|
||||
<svg viewBox="0 0 250 250" width="40" height="40" style="position: absolute; top: 0; border: 0; right: 0; z-index: 99;" aria-hidden="true">
|
||||
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
|
||||
|
||||
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
|
||||
<!--BEGIN TITLEAREA-->
|
||||
<div id="titlearea">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<!--BEGIN PROJECT_LOGO-->
|
||||
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
|
||||
<!--END PROJECT_LOGO-->
|
||||
<!--BEGIN PROJECT_NAME-->
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">$projectname
|
||||
<!--BEGIN PROJECT_NUMBER--> <span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
|
||||
</div>
|
||||
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
|
||||
</td>
|
||||
<!--END PROJECT_NAME-->
|
||||
<!--BEGIN !PROJECT_NAME-->
|
||||
<!--BEGIN PROJECT_BRIEF-->
|
||||
<td style="padding-left: 0.5em;">
|
||||
<div id="projectbrief">$projectbrief</div>
|
||||
</td>
|
||||
<!--END PROJECT_BRIEF-->
|
||||
<!--END !PROJECT_NAME-->
|
||||
<!--BEGIN DISABLE_INDEX-->
|
||||
<!--BEGIN SEARCHENGINE-->
|
||||
<td>$searchbox</td>
|
||||
<!--END SEARCHENGINE-->
|
||||
<!--END DISABLE_INDEX-->
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="theme-selection">
|
||||
<label for="theme-select">Theme:</label>
|
||||
<select id="theme-select">
|
||||
<option value="theme-default">Default</option>
|
||||
<option value="theme-round">Round</option>
|
||||
<option value="theme-robot">Robot</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<!--END TITLEAREA-->
|
||||
<!-- end header part -->
|
||||
@@ -1,62 +0,0 @@
|
||||
html.theme-robot {
|
||||
/* primary theme color. This will affect the entire websites color scheme: links, arrows, labels, ... */
|
||||
--primary-color: #1c89a4;
|
||||
--primary-dark-color: #1a6f84;
|
||||
--primary-light-color: #5abcd4;
|
||||
--primary-lighter-color: #cae1f1;
|
||||
--primary-lightest-color: #e9f1f8;
|
||||
|
||||
--fragment-background: #ececec;
|
||||
--code-background: #ececec;
|
||||
|
||||
/* page base colors */
|
||||
--page-background-color: white;
|
||||
--page-foreground-color: #2c3e50;
|
||||
--page-secondary-foreground-color: #67727e;
|
||||
|
||||
|
||||
--border-radius-large: 0px;
|
||||
--border-radius-small: 0px;
|
||||
--border-radius-medium: 0px;
|
||||
|
||||
--spacing-small: 3px;
|
||||
--spacing-medium: 6px;
|
||||
--spacing-large: 12px;
|
||||
|
||||
--top-height: 125px;
|
||||
|
||||
--side-nav-background: var(--page-background-color);
|
||||
--side-nav-foreground: var(--page-foreground-color);
|
||||
--header-foreground: var(--side-nav-foreground);
|
||||
--searchbar-border-radius: var(--border-radius-medium);
|
||||
--header-background: var(--side-nav-background);
|
||||
--header-foreground: var(--side-nav-foreground);
|
||||
|
||||
--toc-background: rgb(243, 240, 252);
|
||||
--toc-foreground: var(--page-foreground-color);
|
||||
|
||||
--font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;
|
||||
--page-font-size: 14px;
|
||||
--box-shadow: none;
|
||||
--separator-color: #cdcdcd;
|
||||
}
|
||||
|
||||
html.theme-robot.dark-mode {
|
||||
color-scheme: dark;
|
||||
|
||||
--primary-color: #49cad3;
|
||||
--primary-dark-color: #8ed2d7;
|
||||
--primary-light-color: #377479;
|
||||
--primary-lighter-color: #191e21;
|
||||
--primary-lightest-color: #191a1c;
|
||||
|
||||
--fragment-background: #000000;
|
||||
--code-background: #000000;
|
||||
|
||||
--page-background-color: #161616;
|
||||
--page-foreground-color: #d2dbde;
|
||||
--page-secondary-foreground-color: #555555;
|
||||
--separator-color: #545454;
|
||||
--toc-background: #20142C;
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
html.theme-round {
|
||||
/* primary theme color. This will affect the entire websites color scheme: links, arrows, labels, ... */
|
||||
--primary-color: #AF7FE4;
|
||||
--primary-dark-color: #9270E4;
|
||||
--primary-light-color: #d2b7ef;
|
||||
--primary-lighter-color: #cae1f1;
|
||||
--primary-lightest-color: #e9f1f8;
|
||||
|
||||
/* page base colors */
|
||||
--page-background-color: white;
|
||||
--page-foreground-color: #2c3e50;
|
||||
--page-secondary-foreground-color: #67727e;
|
||||
|
||||
|
||||
--border-radius-large: 22px;
|
||||
--border-radius-small: 9px;
|
||||
--border-radius-medium: 14px;
|
||||
--spacing-small: 8px;
|
||||
--spacing-medium: 14px;
|
||||
--spacing-large: 19px;
|
||||
--spacing-xlarge: 21px;
|
||||
|
||||
--top-height: 125px;
|
||||
|
||||
--side-nav-background: #324067;
|
||||
--side-nav-foreground: #F1FDFF;
|
||||
--header-foreground: var(--side-nav-foreground);
|
||||
--searchbar-background: var(--side-nav-foreground);
|
||||
--searchbar-border-radius: var(--border-radius-medium);
|
||||
--header-background: var(--side-nav-background);
|
||||
--header-foreground: var(--side-nav-foreground);
|
||||
|
||||
--toc-background: rgb(243, 240, 252);
|
||||
--toc-foreground: var(--page-foreground-color);
|
||||
}
|
||||
|
||||
html.theme-round.dark-mode {
|
||||
color-scheme: dark;
|
||||
|
||||
--primary-color: #AF7FE4;
|
||||
--primary-dark-color: #715292;
|
||||
--primary-light-color: #ae97c7;
|
||||
--primary-lighter-color: #191e21;
|
||||
--primary-lightest-color: #191a1c;
|
||||
|
||||
--page-background-color: #1C1D1F;
|
||||
--page-foreground-color: #d2dbde;
|
||||
--page-secondary-foreground-color: #859399;
|
||||
--separator-color: #3a3246;
|
||||
--side-nav-background: #171D32;
|
||||
--side-nav-foreground: #F1FDFF;
|
||||
--toc-background: #20142C;
|
||||
--searchbar-background: var(--page-background-color);
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
// Toggle zwischen drei Theme-Zuständen und speichere im localStorage
|
||||
const THEME_CLASSES = ['theme-default', 'theme-round', 'theme-robot'];
|
||||
// Ermögliche das Umschalten per Button/Funktion (z.B. für onclick im HTML)
|
||||
function toggleThemeVariant() {
|
||||
let idx = getCurrentThemeIndex();
|
||||
idx = (idx + 1) % THEME_CLASSES.length;
|
||||
applyThemeClass(idx);
|
||||
}
|
||||
|
||||
// Funktion global verfügbar machen
|
||||
window.toggleThemeVariant = toggleThemeVariant;
|
||||
|
||||
function getCurrentThemeIndex() {
|
||||
const stored = localStorage.getItem('theme-variant');
|
||||
if (stored === null) return 0;
|
||||
const idx = THEME_CLASSES.indexOf(stored);
|
||||
return idx === -1 ? 0 : idx;
|
||||
}
|
||||
|
||||
function applyThemeClass(idx) {
|
||||
document.documentElement.classList.remove(...THEME_CLASSES);
|
||||
if (THEME_CLASSES[idx] && THEME_CLASSES[idx] !== 'theme-default') {
|
||||
document.documentElement.classList.add(THEME_CLASSES[idx]);
|
||||
}
|
||||
localStorage.setItem('theme-variant', THEME_CLASSES[idx] || 'theme-default');
|
||||
// Select synchronisieren, falls vorhanden
|
||||
const select = document.getElementById('theme-select');
|
||||
if (select) select.value = THEME_CLASSES[idx];
|
||||
}
|
||||
|
||||
function setThemeByName(themeName) {
|
||||
const idx = THEME_CLASSES.indexOf(themeName);
|
||||
applyThemeClass(idx === -1 ? 0 : idx);
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const select = document.getElementById('theme-select');
|
||||
if (select) {
|
||||
// Initialisiere Auswahl aus localStorage
|
||||
const idx = getCurrentThemeIndex();
|
||||
select.value = THEME_CLASSES[idx];
|
||||
applyThemeClass(idx);
|
||||
// Theme bei Auswahl ändern
|
||||
select.addEventListener('change', e => {
|
||||
setThemeByName(e.target.value);
|
||||
});
|
||||
} else {
|
||||
// Fallback: Theme trotzdem setzen
|
||||
applyThemeClass(getCurrentThemeIndex());
|
||||
}
|
||||
});
|
||||
82
docs/doxygen-awesome-theme/header.html
Normal file
82
docs/doxygen-awesome-theme/header.html
Normal file
@@ -0,0 +1,82 @@
|
||||
<!-- HTML header for doxygen 1.9.7-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="$langISO">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
|
||||
<meta name="generator" content="Doxygen $doxygenversion"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
|
||||
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
|
||||
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
|
||||
<!--BEGIN DISABLE_INDEX-->
|
||||
<!--BEGIN FULL_SIDEBAR-->
|
||||
<script type="text/javascript">var page_layout=1;</script>
|
||||
<!--END FULL_SIDEBAR-->
|
||||
<!--END DISABLE_INDEX-->
|
||||
<script type="text/javascript" src="$relpath^jquery.js"></script>
|
||||
<script type="text/javascript" src="$relpath^dynsections.js"></script>
|
||||
$treeview
|
||||
$search
|
||||
$mathjax
|
||||
$darkmode
|
||||
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
|
||||
$extrastylesheet
|
||||
<script type="text/javascript" src="$relpath^doxygen-awesome-darkmode-toggle.js"></script>
|
||||
<script type="text/javascript">
|
||||
DoxygenAwesomeDarkModeToggle.init()
|
||||
</script>
|
||||
<script type="text/javascript" src="$relpath^doxygen-awesome-interactive-toc.js"></script>
|
||||
<script type="text/javascript">
|
||||
DoxygenAwesomeInteractiveToc.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<!--BEGIN DISABLE_INDEX-->
|
||||
<!--BEGIN FULL_SIDEBAR-->
|
||||
<div id="side-nav" class="ui-resizable side-nav-resizable"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<!--END FULL_SIDEBAR-->
|
||||
<!--END DISABLE_INDEX-->
|
||||
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
|
||||
<!--BEGIN TITLEAREA-->
|
||||
<div id="titlearea">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr id="projectrow">
|
||||
<!--BEGIN PROJECT_LOGO-->
|
||||
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
|
||||
<!--END PROJECT_LOGO-->
|
||||
<!--BEGIN PROJECT_NAME-->
|
||||
<td id="projectalign">
|
||||
<div id="projectname">$projectname<!--BEGIN PROJECT_NUMBER--><span id="projectnumber"> $projectnumber</span><!--END PROJECT_NUMBER-->
|
||||
</div>
|
||||
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
|
||||
</td>
|
||||
<!--END PROJECT_NAME-->
|
||||
<!--BEGIN !PROJECT_NAME-->
|
||||
<!--BEGIN PROJECT_BRIEF-->
|
||||
<td>
|
||||
<div id="projectbrief">$projectbrief</div>
|
||||
</td>
|
||||
<!--END PROJECT_BRIEF-->
|
||||
<!--END !PROJECT_NAME-->
|
||||
<!--BEGIN DISABLE_INDEX-->
|
||||
<!--BEGIN SEARCHENGINE-->
|
||||
<!--BEGIN !FULL_SIDEBAR-->
|
||||
<td>$searchbox</td>
|
||||
<!--END !FULL_SIDEBAR-->
|
||||
<!--END SEARCHENGINE-->
|
||||
<!--END DISABLE_INDEX-->
|
||||
</tr>
|
||||
<!--BEGIN SEARCHENGINE-->
|
||||
<!--BEGIN FULL_SIDEBAR-->
|
||||
<tr><td colspan="2">$searchbox</td></tr>
|
||||
<!--END FULL_SIDEBAR-->
|
||||
<!--END SEARCHENGINE-->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!--END TITLEAREA-->
|
||||
<!-- end header part -->
|
||||
@@ -1,3 +0,0 @@
|
||||
.github-corner {
|
||||
display: none !important;
|
||||
}
|
||||
@@ -189,7 +189,6 @@ ClioApplication::run(bool const useNgWebServer)
|
||||
|
||||
httpServer->onGet("/metrics", MetricsHandler{adminVerifier});
|
||||
httpServer->onGet("/health", HealthCheckHandler{});
|
||||
httpServer->onGet("/cache_state", CacheStateHandler{cache});
|
||||
auto requestHandler = RequestHandler{adminVerifier, handler};
|
||||
httpServer->onPost("/", requestHandler);
|
||||
httpServer->onWs(std::move(requestHandler));
|
||||
@@ -215,7 +214,7 @@ ClioApplication::run(bool const useNgWebServer)
|
||||
// Init the web server
|
||||
auto handler = std::make_shared<web::RPCServerHandler<RPCEngineType>>(config_, backend, rpcEngine, etl, dosGuard);
|
||||
|
||||
auto const httpServer = web::makeHttpServer(config_, ioc, dosGuard, handler, cache);
|
||||
auto const httpServer = web::makeHttpServer(config_, ioc, dosGuard, handler);
|
||||
|
||||
// Blocks until stopped.
|
||||
// When stopped, shared_ptrs fall out of scope
|
||||
|
||||
@@ -120,34 +120,4 @@ HealthCheckHandler::operator()(
|
||||
return web::ng::Response{boost::beast::http::status::ok, kHEALTH_CHECK_HTML, request};
|
||||
}
|
||||
|
||||
web::ng::Response
|
||||
CacheStateHandler::operator()(
|
||||
web::ng::Request const& request,
|
||||
web::ng::ConnectionMetadata&,
|
||||
web::SubscriptionContextPtr,
|
||||
boost::asio::yield_context
|
||||
)
|
||||
{
|
||||
static constexpr auto kCACHE_CHECK_LOADED_HTML = R"html(
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title>Cache state</title></head>
|
||||
<body><h1>Cache state</h1><p>Cache is fully loaded</p></body>
|
||||
</html>
|
||||
)html";
|
||||
|
||||
static constexpr auto kCACHE_CHECK_NOT_LOADED_HTML = R"html(
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title>Cache state</title></head>
|
||||
<body><h1>Cache state</h1><p>Cache is not yet loaded</p></body>
|
||||
</html>
|
||||
)html";
|
||||
|
||||
if (cache_.get().isFull())
|
||||
return web::ng::Response{boost::beast::http::status::ok, kCACHE_CHECK_LOADED_HTML, request};
|
||||
|
||||
return web::ng::Response{boost::beast::http::status::service_unavailable, kCACHE_CHECK_NOT_LOADED_HTML, request};
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "data/LedgerCacheInterface.hpp"
|
||||
#include "rpc/Errors.hpp"
|
||||
#include "util/log/Logger.hpp"
|
||||
#include "web/AdminVerificationStrategy.hpp"
|
||||
@@ -164,37 +163,6 @@ public:
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A function object that handles the cache state check endpoint.
|
||||
*/
|
||||
class CacheStateHandler {
|
||||
std::reference_wrapper<data::LedgerCacheInterface const> cache_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new CacheStateHandler object.
|
||||
*
|
||||
* @param cache The ledger cache to use.
|
||||
*/
|
||||
CacheStateHandler(data::LedgerCacheInterface const& cache) : cache_{cache}
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The call of the function object.
|
||||
*
|
||||
* @param request The request to handle.
|
||||
* @return The response to the request
|
||||
*/
|
||||
web::ng::Response
|
||||
operator()(
|
||||
web::ng::Request const& request,
|
||||
web::ng::ConnectionMetadata&,
|
||||
web::SubscriptionContextPtr,
|
||||
boost::asio::yield_context
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A function object that handles the websocket endpoint.
|
||||
*
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
#include "data/BackendInterface.hpp"
|
||||
#include "data/CassandraBackend.hpp"
|
||||
#include "data/KeyspaceBackend.hpp"
|
||||
#include "data/LedgerCacheInterface.hpp"
|
||||
#include "data/cassandra/SettingsProvider.hpp"
|
||||
#include "util/config/ConfigDefinition.hpp"
|
||||
@@ -56,15 +55,9 @@ makeBackend(util::config::ClioConfigDefinition const& config, data::LedgerCacheI
|
||||
|
||||
if (boost::iequals(type, "cassandra")) {
|
||||
auto const cfg = config.getObject("database." + type);
|
||||
if (cfg.getValueView("provider").asString() == toString(cassandra::impl::Provider::Keyspace)) {
|
||||
backend = std::make_shared<data::cassandra::KeyspaceBackend>(
|
||||
data::cassandra::SettingsProvider{cfg}, cache, readOnly
|
||||
);
|
||||
} else {
|
||||
backend = std::make_shared<data::cassandra::CassandraBackend>(
|
||||
data::cassandra::SettingsProvider{cfg}, cache, readOnly
|
||||
);
|
||||
}
|
||||
backend = std::make_shared<data::cassandra::CassandraBackend>(
|
||||
data::cassandra::SettingsProvider{cfg}, cache, readOnly
|
||||
);
|
||||
}
|
||||
|
||||
if (!backend)
|
||||
|
||||
@@ -295,7 +295,7 @@ public:
|
||||
* @param account The account to fetch transactions for
|
||||
* @param limit The maximum number of transactions per result page
|
||||
* @param forward Whether to fetch the page forwards or backwards from the given cursor
|
||||
* @param txnCursor The cursor to resume fetching from
|
||||
* @param cursor The cursor to resume fetching from
|
||||
* @param yield The coroutine context
|
||||
* @return Results and a cursor to resume from
|
||||
*/
|
||||
@@ -304,7 +304,7 @@ public:
|
||||
ripple::AccountID const& account,
|
||||
std::uint32_t limit,
|
||||
bool forward,
|
||||
std::optional<TransactionsCursor> const& txnCursor,
|
||||
std::optional<TransactionsCursor> const& cursor,
|
||||
boost::asio::yield_context yield
|
||||
) const = 0;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,308 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of clio: https://github.com/XRPLF/clio
|
||||
Copyright (c) 2025, the clio developers.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "data/LedgerHeaderCache.hpp"
|
||||
#include "data/Types.hpp"
|
||||
#include "data/cassandra/CassandraBackendFamily.hpp"
|
||||
#include "data/cassandra/Concepts.hpp"
|
||||
#include "data/cassandra/KeyspaceSchema.hpp"
|
||||
#include "data/cassandra/SettingsProvider.hpp"
|
||||
#include "data/cassandra/Types.hpp"
|
||||
#include "data/cassandra/impl/ExecutionStrategy.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/log/Logger.hpp"
|
||||
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/json/object.hpp>
|
||||
#include <boost/uuid/string_generator.hpp>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <cassandra.h>
|
||||
#include <fmt/format.h>
|
||||
#include <xrpl/basics/Blob.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/strHex.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerHeader.h>
|
||||
#include <xrpl/protocol/nft.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace data::cassandra {
|
||||
|
||||
/**
|
||||
* @brief Implements @ref CassandraBackendFamily for Keyspace
|
||||
*
|
||||
* @tparam SettingsProviderType The settings provider type to use
|
||||
* @tparam ExecutionStrategyType The execution strategy type to use
|
||||
* @tparam FetchLedgerCacheType The ledger header cache type to use
|
||||
*/
|
||||
template <
|
||||
SomeSettingsProvider SettingsProviderType,
|
||||
SomeExecutionStrategy ExecutionStrategyType,
|
||||
typename FetchLedgerCacheType = FetchLedgerCache>
|
||||
class BasicKeyspaceBackend : public CassandraBackendFamily<
|
||||
SettingsProviderType,
|
||||
ExecutionStrategyType,
|
||||
KeyspaceSchema<SettingsProviderType>,
|
||||
FetchLedgerCacheType> {
|
||||
using DefaultCassandraFamily = CassandraBackendFamily<
|
||||
SettingsProviderType,
|
||||
ExecutionStrategyType,
|
||||
KeyspaceSchema<SettingsProviderType>,
|
||||
FetchLedgerCacheType>;
|
||||
|
||||
using DefaultCassandraFamily::executor_;
|
||||
using DefaultCassandraFamily::ledgerSequence_;
|
||||
using DefaultCassandraFamily::log_;
|
||||
using DefaultCassandraFamily::range_;
|
||||
using DefaultCassandraFamily::schema_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Inherit the constructors of the base class.
|
||||
*/
|
||||
using DefaultCassandraFamily::DefaultCassandraFamily;
|
||||
|
||||
/**
|
||||
* @brief Move constructor is deleted because handle_ is shared by reference with executor
|
||||
*/
|
||||
BasicKeyspaceBackend(BasicKeyspaceBackend&&) = delete;
|
||||
|
||||
bool
|
||||
doFinishWrites() override
|
||||
{
|
||||
this->waitForWritesToFinish();
|
||||
|
||||
// !range_.has_value() means the table 'ledger_range' is not populated;
|
||||
// This would be the first write to the table.
|
||||
// In this case, insert both min_sequence/max_sequence range into the table.
|
||||
if (not(range_.has_value())) {
|
||||
executor_.writeSync(schema_->insertLedgerRange, false, ledgerSequence_);
|
||||
executor_.writeSync(schema_->insertLedgerRange, true, ledgerSequence_);
|
||||
}
|
||||
|
||||
if (not this->executeSyncUpdate(schema_->updateLedgerRange.bind(ledgerSequence_, true, ledgerSequence_ - 1))) {
|
||||
log_.warn() << "Update failed for ledger " << ledgerSequence_;
|
||||
return false;
|
||||
}
|
||||
|
||||
log_.info() << "Committed ledger " << ledgerSequence_;
|
||||
return true;
|
||||
}
|
||||
|
||||
NFTsAndCursor
|
||||
fetchNFTsByIssuer(
|
||||
ripple::AccountID const& issuer,
|
||||
std::optional<std::uint32_t> const& taxon,
|
||||
std::uint32_t const ledgerSequence,
|
||||
std::uint32_t const limit,
|
||||
std::optional<ripple::uint256> const& cursorIn,
|
||||
boost::asio::yield_context yield
|
||||
) const override
|
||||
{
|
||||
std::vector<ripple::uint256> nftIDs;
|
||||
if (taxon.has_value()) {
|
||||
// Keyspace and ScyllaDB uses the same logic for taxon-filtered queries
|
||||
nftIDs = fetchNFTIDsByTaxon(issuer, *taxon, limit, cursorIn, yield);
|
||||
} else {
|
||||
// --- Amazon Keyspaces Workflow for non-taxon queries ---
|
||||
auto const startTaxon = cursorIn.has_value() ? ripple::nft::toUInt32(ripple::nft::getTaxon(*cursorIn)) : 0;
|
||||
auto const startTokenID = cursorIn.value_or(ripple::uint256(0));
|
||||
|
||||
Statement firstQuery = schema_->selectNFTIDsByIssuerTaxon.bind(issuer);
|
||||
firstQuery.bindAt(1, startTaxon);
|
||||
firstQuery.bindAt(2, startTokenID);
|
||||
firstQuery.bindAt(3, Limit{limit});
|
||||
|
||||
auto const firstRes = executor_.read(yield, firstQuery);
|
||||
if (firstRes) {
|
||||
for (auto const [nftID] : extract<ripple::uint256>(firstRes.value()))
|
||||
nftIDs.push_back(nftID);
|
||||
}
|
||||
|
||||
if (nftIDs.size() < limit) {
|
||||
auto const remainingLimit = limit - nftIDs.size();
|
||||
Statement secondQuery = schema_->selectNFTsAfterTaxonKeyspaces.bind(issuer);
|
||||
secondQuery.bindAt(1, startTaxon);
|
||||
secondQuery.bindAt(2, Limit{remainingLimit});
|
||||
|
||||
auto const secondRes = executor_.read(yield, secondQuery);
|
||||
if (secondRes) {
|
||||
for (auto const [nftID] : extract<ripple::uint256>(secondRes.value()))
|
||||
nftIDs.push_back(nftID);
|
||||
}
|
||||
}
|
||||
}
|
||||
return populateNFTsAndCreateCursor(nftIDs, ledgerSequence, limit, yield);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief (Unsupported in Keyspaces) Fetches account root object indexes by page.
|
||||
* * @note Loading the cache by enumerating all accounts is currently unsupported by the AWS Keyspaces backend.
|
||||
* This function's logic relies on "PER PARTITION LIMIT 1", which Keyspaces does not support, and there is
|
||||
* no efficient alternative. This is acceptable as the cache is primarily loaded via diffs. Calling this
|
||||
* function will throw an exception.
|
||||
*
|
||||
* @param number The total number of accounts to fetch.
|
||||
* @param pageSize The maximum number of accounts per page.
|
||||
* @param seq The accounts need to exist at this ledger sequence.
|
||||
* @param yield The coroutine context.
|
||||
* @return A vector of ripple::uint256 representing the account root hashes.
|
||||
*/
|
||||
std::vector<ripple::uint256>
|
||||
fetchAccountRoots(
|
||||
[[maybe_unused]] std::uint32_t number,
|
||||
[[maybe_unused]] std::uint32_t pageSize,
|
||||
[[maybe_unused]] std::uint32_t seq,
|
||||
[[maybe_unused]] boost::asio::yield_context yield
|
||||
) const override
|
||||
{
|
||||
ASSERT(false, "Fetching account roots is not supported by the Keyspaces backend.");
|
||||
std::unreachable();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<ripple::uint256>
|
||||
fetchNFTIDsByTaxon(
|
||||
ripple::AccountID const& issuer,
|
||||
std::uint32_t const taxon,
|
||||
std::uint32_t const limit,
|
||||
std::optional<ripple::uint256> const& cursorIn,
|
||||
boost::asio::yield_context yield
|
||||
) const
|
||||
{
|
||||
std::vector<ripple::uint256> nftIDs;
|
||||
Statement statement = schema_->selectNFTIDsByIssuerTaxon.bind(issuer);
|
||||
statement.bindAt(1, taxon);
|
||||
statement.bindAt(2, cursorIn.value_or(ripple::uint256(0)));
|
||||
statement.bindAt(3, Limit{limit});
|
||||
|
||||
auto const res = executor_.read(yield, statement);
|
||||
if (res && res.value().hasRows()) {
|
||||
for (auto const [nftID] : extract<ripple::uint256>(res.value()))
|
||||
nftIDs.push_back(nftID);
|
||||
}
|
||||
return nftIDs;
|
||||
}
|
||||
|
||||
std::vector<ripple::uint256>
|
||||
fetchNFTIDsWithoutTaxon(
|
||||
ripple::AccountID const& issuer,
|
||||
std::uint32_t const limit,
|
||||
std::optional<ripple::uint256> const& cursorIn,
|
||||
boost::asio::yield_context yield
|
||||
) const
|
||||
{
|
||||
std::vector<ripple::uint256> nftIDs;
|
||||
|
||||
auto const startTaxon = cursorIn.has_value() ? ripple::nft::toUInt32(ripple::nft::getTaxon(*cursorIn)) : 0;
|
||||
auto const startTokenID = cursorIn.value_or(ripple::uint256(0));
|
||||
|
||||
Statement firstQuery = schema_->selectNFTIDsByIssuerTaxon.bind(issuer);
|
||||
firstQuery.bindAt(1, startTaxon);
|
||||
firstQuery.bindAt(2, startTokenID);
|
||||
firstQuery.bindAt(3, Limit{limit});
|
||||
|
||||
auto const firstRes = executor_.read(yield, firstQuery);
|
||||
if (firstRes) {
|
||||
for (auto const [nftID] : extract<ripple::uint256>(firstRes.value()))
|
||||
nftIDs.push_back(nftID);
|
||||
}
|
||||
|
||||
if (nftIDs.size() < limit) {
|
||||
auto const remainingLimit = limit - nftIDs.size();
|
||||
Statement secondQuery = schema_->selectNFTsAfterTaxonKeyspaces.bind(issuer);
|
||||
secondQuery.bindAt(1, startTaxon);
|
||||
secondQuery.bindAt(2, Limit{remainingLimit});
|
||||
|
||||
auto const secondRes = executor_.read(yield, secondQuery);
|
||||
if (secondRes) {
|
||||
for (auto const [nftID] : extract<ripple::uint256>(secondRes.value()))
|
||||
nftIDs.push_back(nftID);
|
||||
}
|
||||
}
|
||||
return nftIDs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Takes a list of NFT IDs, fetches their full data, and assembles the final result with a cursor.
|
||||
*/
|
||||
NFTsAndCursor
|
||||
populateNFTsAndCreateCursor(
|
||||
std::vector<ripple::uint256> const& nftIDs,
|
||||
std::uint32_t const ledgerSequence,
|
||||
std::uint32_t const limit,
|
||||
boost::asio::yield_context yield
|
||||
) const
|
||||
{
|
||||
if (nftIDs.empty()) {
|
||||
LOG(log_.debug()) << "No rows returned";
|
||||
return {};
|
||||
}
|
||||
|
||||
NFTsAndCursor ret;
|
||||
if (nftIDs.size() == limit)
|
||||
ret.cursor = nftIDs.back();
|
||||
|
||||
// Prepare and execute queries to fetch NFT info and URIs in parallel.
|
||||
std::vector<Statement> selectNFTStatements;
|
||||
selectNFTStatements.reserve(nftIDs.size());
|
||||
std::transform(
|
||||
std::cbegin(nftIDs), std::cend(nftIDs), std::back_inserter(selectNFTStatements), [&](auto const& nftID) {
|
||||
return schema_->selectNFT.bind(nftID, ledgerSequence);
|
||||
}
|
||||
);
|
||||
|
||||
std::vector<Statement> selectNFTURIStatements;
|
||||
selectNFTURIStatements.reserve(nftIDs.size());
|
||||
std::transform(
|
||||
std::cbegin(nftIDs), std::cend(nftIDs), std::back_inserter(selectNFTURIStatements), [&](auto const& nftID) {
|
||||
return schema_->selectNFTURI.bind(nftID, ledgerSequence);
|
||||
}
|
||||
);
|
||||
|
||||
auto const nftInfos = executor_.readEach(yield, selectNFTStatements);
|
||||
auto const nftUris = executor_.readEach(yield, selectNFTURIStatements);
|
||||
|
||||
// Combine the results into final NFT objects.
|
||||
for (auto i = 0u; i < nftIDs.size(); ++i) {
|
||||
if (auto const maybeRow = nftInfos[i].template get<uint32_t, ripple::AccountID, bool>(); maybeRow) {
|
||||
auto [seq, owner, isBurned] = *maybeRow;
|
||||
NFT nft(nftIDs[i], seq, owner, isBurned);
|
||||
if (auto const maybeUri = nftUris[i].template get<ripple::Blob>(); maybeUri)
|
||||
nft.uri = *maybeUri;
|
||||
ret.nfts.push_back(nft);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
using KeyspaceBackend = BasicKeyspaceBackend<SettingsProvider, impl::DefaultExecutionStrategy<>>;
|
||||
|
||||
} // namespace data::cassandra
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,178 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of clio: https://github.com/XRPLF/clio
|
||||
Copyright (c) 2025, the clio developers.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "data/cassandra/Concepts.hpp"
|
||||
#include "data/cassandra/Handle.hpp"
|
||||
#include "data/cassandra/Schema.hpp"
|
||||
#include "data/cassandra/SettingsProvider.hpp"
|
||||
#include "data/cassandra/Types.hpp"
|
||||
#include "util/log/Logger.hpp"
|
||||
|
||||
#include <boost/json/string.hpp>
|
||||
#include <fmt/compile.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace data::cassandra {
|
||||
|
||||
/**
|
||||
* @brief Manages the DB schema and provides access to prepared statements.
|
||||
*/
|
||||
template <SomeSettingsProvider SettingsProviderType>
|
||||
class CassandraSchema : public Schema<SettingsProvider> {
|
||||
using Schema::Schema;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new Cassandra Schema object
|
||||
*
|
||||
* @param settingsProvider The settings provider
|
||||
*/
|
||||
struct CassandraStatements : public Schema<SettingsProvider>::Statements {
|
||||
using Schema<SettingsProvider>::Statements::Statements;
|
||||
|
||||
//
|
||||
// Update (and "delete") queries
|
||||
//
|
||||
PreparedStatement updateLedgerRange = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
R"(
|
||||
UPDATE {}
|
||||
SET sequence = ?
|
||||
WHERE is_latest = ?
|
||||
IF sequence IN (?, null)
|
||||
)",
|
||||
qualifiedTableName(settingsProvider_.get(), "ledger_range")
|
||||
)
|
||||
);
|
||||
}();
|
||||
|
||||
//
|
||||
// Select queries
|
||||
//
|
||||
|
||||
PreparedStatement selectNFTIDsByIssuer = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
R"(
|
||||
SELECT token_id
|
||||
FROM {}
|
||||
WHERE issuer = ?
|
||||
AND (taxon, token_id) > ?
|
||||
ORDER BY taxon ASC, token_id ASC
|
||||
LIMIT ?
|
||||
)",
|
||||
qualifiedTableName(settingsProvider_.get(), "issuer_nf_tokens_v2")
|
||||
)
|
||||
);
|
||||
}();
|
||||
|
||||
PreparedStatement selectAccountFromBeginning = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
R"(
|
||||
SELECT account
|
||||
FROM {}
|
||||
WHERE token(account) > 0
|
||||
PER PARTITION LIMIT 1
|
||||
LIMIT ?
|
||||
)",
|
||||
qualifiedTableName(settingsProvider_.get(), "account_tx")
|
||||
)
|
||||
);
|
||||
}();
|
||||
|
||||
PreparedStatement selectAccountFromToken = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
R"(
|
||||
SELECT account
|
||||
FROM {}
|
||||
WHERE token(account) > token(?)
|
||||
PER PARTITION LIMIT 1
|
||||
LIMIT ?
|
||||
)",
|
||||
qualifiedTableName(settingsProvider_.get(), "account_tx")
|
||||
)
|
||||
);
|
||||
}();
|
||||
|
||||
PreparedStatement selectLedgerPageKeys = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
R"(
|
||||
SELECT key
|
||||
FROM {}
|
||||
WHERE TOKEN(key) >= ?
|
||||
AND sequence <= ?
|
||||
PER PARTITION LIMIT 1
|
||||
LIMIT ?
|
||||
ALLOW FILTERING
|
||||
)",
|
||||
qualifiedTableName(settingsProvider_.get(), "objects")
|
||||
)
|
||||
);
|
||||
}();
|
||||
|
||||
PreparedStatement selectLedgerPage = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
R"(
|
||||
SELECT object, key
|
||||
FROM {}
|
||||
WHERE TOKEN(key) >= ?
|
||||
AND sequence <= ?
|
||||
PER PARTITION LIMIT 1
|
||||
LIMIT ?
|
||||
ALLOW FILTERING
|
||||
)",
|
||||
qualifiedTableName(settingsProvider_.get(), "objects")
|
||||
)
|
||||
);
|
||||
}();
|
||||
};
|
||||
|
||||
void
|
||||
prepareStatements(Handle const& handle) override
|
||||
{
|
||||
LOG(log_.info()) << "Preparing cassandra statements";
|
||||
statements_ = std::make_unique<CassandraStatements>(settingsProvider_, handle);
|
||||
LOG(log_.info()) << "Finished preparing statements";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Provides access to statements.
|
||||
*
|
||||
* @return The statements
|
||||
*/
|
||||
std::unique_ptr<CassandraStatements> const&
|
||||
operator->() const
|
||||
{
|
||||
return statements_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<CassandraStatements> statements_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace data::cassandra
|
||||
@@ -1,140 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of clio: https://github.com/XRPLF/clio
|
||||
Copyright (c) 2025, the clio developers.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "data/cassandra/Concepts.hpp"
|
||||
#include "data/cassandra/Handle.hpp"
|
||||
#include "data/cassandra/Schema.hpp"
|
||||
#include "data/cassandra/SettingsProvider.hpp"
|
||||
#include "data/cassandra/Types.hpp"
|
||||
#include "util/log/Logger.hpp"
|
||||
|
||||
#include <boost/json/string.hpp>
|
||||
#include <fmt/compile.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace data::cassandra {
|
||||
|
||||
/**
|
||||
* @brief Manages the DB schema and provides access to prepared statements.
|
||||
*/
|
||||
template <SomeSettingsProvider SettingsProviderType>
|
||||
class KeyspaceSchema : public Schema<SettingsProvider> {
|
||||
public:
|
||||
using Schema::Schema;
|
||||
|
||||
/**
|
||||
* @brief Construct a new Keyspace Schema object
|
||||
*
|
||||
* @param settingsProvider The settings provider
|
||||
*/
|
||||
struct KeyspaceStatements : public Schema<SettingsProvider>::Statements {
|
||||
using Schema<SettingsProvider>::Statements::Statements;
|
||||
|
||||
//
|
||||
// Insert queries
|
||||
//
|
||||
PreparedStatement insertLedgerRange = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
R"(
|
||||
INSERT INTO {} (is_latest, sequence) VALUES (?, ?) IF NOT EXISTS
|
||||
)",
|
||||
qualifiedTableName(settingsProvider_.get(), "ledger_range")
|
||||
)
|
||||
);
|
||||
}();
|
||||
|
||||
//
|
||||
// Update (and "delete") queries
|
||||
//
|
||||
PreparedStatement updateLedgerRange = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
R"(
|
||||
UPDATE {}
|
||||
SET sequence = ?
|
||||
WHERE is_latest = ?
|
||||
IF sequence = ?
|
||||
)",
|
||||
qualifiedTableName(settingsProvider_.get(), "ledger_range")
|
||||
)
|
||||
);
|
||||
}();
|
||||
|
||||
PreparedStatement selectLedgerRange = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
R"(
|
||||
SELECT sequence
|
||||
FROM {}
|
||||
WHERE is_latest in (True, False)
|
||||
)",
|
||||
qualifiedTableName(settingsProvider_.get(), "ledger_range")
|
||||
)
|
||||
);
|
||||
}();
|
||||
|
||||
//
|
||||
// Select queries
|
||||
//
|
||||
PreparedStatement selectNFTsAfterTaxonKeyspaces = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
R"(
|
||||
SELECT token_id
|
||||
FROM {}
|
||||
WHERE issuer = ?
|
||||
AND taxon > ?
|
||||
ORDER BY taxon ASC, token_id ASC
|
||||
LIMIT ?
|
||||
)",
|
||||
qualifiedTableName(settingsProvider_.get(), "issuer_nf_tokens_v2")
|
||||
)
|
||||
);
|
||||
}();
|
||||
};
|
||||
|
||||
void
|
||||
prepareStatements(Handle const& handle) override
|
||||
{
|
||||
LOG(log_.info()) << "Preparing aws keyspace statements";
|
||||
statements_ = std::make_unique<KeyspaceStatements>(settingsProvider_, handle);
|
||||
LOG(log_.info()) << "Finished preparing statements";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Provides access to statements.
|
||||
*
|
||||
* @return The statements
|
||||
*/
|
||||
std::unique_ptr<KeyspaceStatements> const&
|
||||
operator->() const
|
||||
{
|
||||
return statements_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<KeyspaceStatements> statements_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace data::cassandra
|
||||
@@ -24,10 +24,11 @@
|
||||
#include "data/cassandra/Types.hpp"
|
||||
#include "util/log/Logger.hpp"
|
||||
|
||||
#include <boost/json/string.hpp>
|
||||
#include <fmt/compile.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
@@ -53,15 +54,12 @@ template <SomeSettingsProvider SettingsProviderType>
|
||||
*/
|
||||
template <SomeSettingsProvider SettingsProviderType>
|
||||
class Schema {
|
||||
protected:
|
||||
util::Logger log_{"Backend"};
|
||||
std::reference_wrapper<SettingsProviderType const> settingsProvider_;
|
||||
|
||||
public:
|
||||
virtual ~Schema() = default;
|
||||
|
||||
/**
|
||||
* @brief Shared Schema's between all Schema classes (Cassandra and Keyspace)
|
||||
* @brief Construct a new Schema object
|
||||
*
|
||||
* @param settingsProvider The settings provider
|
||||
*/
|
||||
@@ -337,7 +335,6 @@ public:
|
||||
* @brief Prepared statements holder.
|
||||
*/
|
||||
class Statements {
|
||||
protected:
|
||||
std::reference_wrapper<SettingsProviderType const> settingsProvider_;
|
||||
std::reference_wrapper<Handle const> handle_;
|
||||
|
||||
@@ -351,6 +348,86 @@ public:
|
||||
Statements(SettingsProviderType const& settingsProvider, Handle const& handle)
|
||||
: settingsProvider_{settingsProvider}, handle_{std::cref(handle)}
|
||||
{
|
||||
// initialize scylladb supported queries
|
||||
if (settingsProvider_.get().getSettings().provider == "scylladb") {
|
||||
selectAccountFromBeginningScylla = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
R"(
|
||||
SELECT account
|
||||
FROM {}
|
||||
WHERE token(account) > 0
|
||||
PER PARTITION LIMIT 1
|
||||
LIMIT ?
|
||||
)",
|
||||
qualifiedTableName(settingsProvider_.get(), "account_tx")
|
||||
)
|
||||
);
|
||||
}();
|
||||
|
||||
selectAccountFromTokenScylla = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
R"(
|
||||
SELECT account
|
||||
FROM {}
|
||||
WHERE token(account) > token(?)
|
||||
PER PARTITION LIMIT 1
|
||||
LIMIT ?
|
||||
)",
|
||||
qualifiedTableName(settingsProvider_.get(), "account_tx")
|
||||
)
|
||||
);
|
||||
}();
|
||||
|
||||
selectNFTsByIssuerScylla = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
R"(
|
||||
SELECT token_id
|
||||
FROM {}
|
||||
WHERE issuer = ?
|
||||
AND (taxon, token_id) > ?
|
||||
ORDER BY taxon ASC, token_id ASC
|
||||
LIMIT ?
|
||||
)",
|
||||
qualifiedTableName(settingsProvider_.get(), "issuer_nf_tokens_v2")
|
||||
)
|
||||
);
|
||||
}();
|
||||
|
||||
updateLedgerRange = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
R"(
|
||||
UPDATE {}
|
||||
SET sequence = ?
|
||||
WHERE is_latest = ?
|
||||
IF sequence IN (?, null)
|
||||
)",
|
||||
qualifiedTableName(settingsProvider_.get(), "ledger_range")
|
||||
)
|
||||
);
|
||||
}();
|
||||
|
||||
// AWS_keyspace supported queries
|
||||
} else if (settingsProvider_.get().getSettings().provider == "aws_keyspace") {
|
||||
selectNFTsAfterTaxonKeyspaces = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
R"(
|
||||
SELECT token_id
|
||||
FROM {}
|
||||
WHERE issuer = ?
|
||||
AND taxon > ?
|
||||
ORDER BY taxon ASC, token_id ASC
|
||||
LIMIT ?
|
||||
)",
|
||||
qualifiedTableName(settingsProvider_.get(), "issuer_nf_tokens_v2")
|
||||
)
|
||||
);
|
||||
}();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -530,6 +607,31 @@ public:
|
||||
// Update (and "delete") queries
|
||||
//
|
||||
|
||||
PreparedStatement insertLedgerRange = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
R"(
|
||||
INSERT INTO {} (is_latest, sequence) VALUES (?, ?) IF NOT EXISTS
|
||||
)",
|
||||
qualifiedTableName(settingsProvider_.get(), "ledger_range")
|
||||
)
|
||||
);
|
||||
}();
|
||||
|
||||
PreparedStatement updateLedgerRange = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
R"(
|
||||
UPDATE {}
|
||||
SET sequence = ?
|
||||
WHERE is_latest = ?
|
||||
IF sequence = ?
|
||||
)",
|
||||
qualifiedTableName(settingsProvider_.get(), "ledger_range")
|
||||
)
|
||||
);
|
||||
}();
|
||||
|
||||
PreparedStatement deleteLedgerRange = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
@@ -644,6 +746,45 @@ public:
|
||||
);
|
||||
}();
|
||||
|
||||
/*
|
||||
Currently, these two SELECT statements is not used.
|
||||
If we ever use them, will need to change the PER PARTITION LIMIT to support for Keyspace
|
||||
|
||||
PreparedStatement selectLedgerPageKeys = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
R"(
|
||||
SELECT key
|
||||
FROM {}
|
||||
WHERE TOKEN(key) >= ?
|
||||
AND sequence <= ?
|
||||
PER PARTITION LIMIT 1
|
||||
LIMIT ?
|
||||
ALLOW FILTERING
|
||||
)",
|
||||
qualifiedTableName(settingsProvider_.get(), "objects")
|
||||
)
|
||||
);
|
||||
}();
|
||||
|
||||
PreparedStatement selectLedgerPage = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
R"(
|
||||
SELECT object, key
|
||||
FROM {}
|
||||
WHERE TOKEN(key) >= ?
|
||||
AND sequence <= ?
|
||||
PER PARTITION LIMIT 1
|
||||
LIMIT ?
|
||||
ALLOW FILTERING
|
||||
)",
|
||||
qualifiedTableName(settingsProvider_.get(), "objects")
|
||||
)
|
||||
);
|
||||
}();
|
||||
*/
|
||||
|
||||
PreparedStatement getToken = [this]() {
|
||||
return handle_.get().prepare(
|
||||
fmt::format(
|
||||
@@ -863,6 +1004,15 @@ public:
|
||||
)
|
||||
);
|
||||
}();
|
||||
|
||||
// For ScyllaDB / Cassandra ONLY
|
||||
std::optional<PreparedStatement> selectAccountFromBeginningScylla;
|
||||
std::optional<PreparedStatement> selectAccountFromTokenScylla;
|
||||
std::optional<PreparedStatement> selectNFTsByIssuerScylla;
|
||||
|
||||
// For AWS Keyspaces ONLY
|
||||
// NOTE: AWS keyspace is not able to load cache with accounts
|
||||
std::optional<PreparedStatement> selectNFTsAfterTaxonKeyspaces;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -870,8 +1020,27 @@ public:
|
||||
*
|
||||
* @param handle The handle to the DB
|
||||
*/
|
||||
virtual void
|
||||
prepareStatements(Handle const& handle) = 0;
|
||||
void
|
||||
prepareStatements(Handle const& handle)
|
||||
{
|
||||
LOG(log_.info()) << "Preparing cassandra statements";
|
||||
statements_ = std::make_unique<Statements>(settingsProvider_, handle);
|
||||
LOG(log_.info()) << "Finished preparing statements";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Provides access to statements.
|
||||
*
|
||||
* @return The statements
|
||||
*/
|
||||
std::unique_ptr<Statements> const&
|
||||
operator->() const
|
||||
{
|
||||
return statements_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Statements> statements_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace data::cassandra
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
#include <utility>
|
||||
|
||||
namespace data::cassandra {
|
||||
namespace impl {
|
||||
|
||||
namespace impl {
|
||||
struct Settings;
|
||||
class Session;
|
||||
class Cluster;
|
||||
@@ -36,7 +36,6 @@ struct Result;
|
||||
class Statement;
|
||||
class PreparedStatement;
|
||||
struct Batch;
|
||||
|
||||
} // namespace impl
|
||||
|
||||
using Settings = impl::Settings;
|
||||
|
||||
@@ -61,12 +61,8 @@ Cluster::Cluster(Settings const& settings) : ManagedObject{cass_cluster_new(), k
|
||||
cass_cluster_set_request_timeout(*this, settings.requestTimeout.count());
|
||||
|
||||
// TODO: AWS keyspace reads should be local_one to save cost
|
||||
if (settings.provider == toString(cassandra::impl::Provider::Keyspace)) {
|
||||
if (settings.provider == "aws_keyspace") {
|
||||
if (auto const rc = cass_cluster_set_consistency(*this, CASS_CONSISTENCY_LOCAL_QUORUM); rc != CASS_OK) {
|
||||
throw std::runtime_error(fmt::format("Error setting keyspace consistency: {}", cass_error_desc(rc)));
|
||||
}
|
||||
} else {
|
||||
if (auto const rc = cass_cluster_set_consistency(*this, CASS_CONSISTENCY_QUORUM); rc != CASS_OK) {
|
||||
throw std::runtime_error(fmt::format("Error setting cassandra consistency: {}", cass_error_desc(rc)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,29 +31,10 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
namespace data::cassandra::impl {
|
||||
|
||||
namespace {
|
||||
|
||||
enum class Provider { Cassandra, Keyspace };
|
||||
|
||||
inline std::string
|
||||
toString(Provider provider)
|
||||
{
|
||||
switch (provider) {
|
||||
case Provider::Cassandra:
|
||||
return "cassandra";
|
||||
case Provider::Keyspace:
|
||||
return "aws_keyspace";
|
||||
}
|
||||
std::unreachable();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// TODO: move Settings to public interface, not impl
|
||||
|
||||
/**
|
||||
@@ -64,7 +45,7 @@ struct Settings {
|
||||
static constexpr uint32_t kDEFAULT_MAX_WRITE_REQUESTS_OUTSTANDING = 10'000;
|
||||
static constexpr uint32_t kDEFAULT_MAX_READ_REQUESTS_OUTSTANDING = 100'000;
|
||||
static constexpr std::size_t kDEFAULT_BATCH_SIZE = 20;
|
||||
static constexpr Provider kDEFAULT_PROVIDER = Provider::Cassandra;
|
||||
static constexpr std::string kDEFAULT_PROVIDER = "cassandra";
|
||||
|
||||
/**
|
||||
* @brief Represents the configuration of contact points for cassandra.
|
||||
@@ -109,7 +90,7 @@ struct Settings {
|
||||
std::size_t writeBatchSize = kDEFAULT_BATCH_SIZE;
|
||||
|
||||
/** @brief Provider to know if we are using scylladb or keyspace */
|
||||
std::string provider = toString(kDEFAULT_PROVIDER);
|
||||
std::string provider = kDEFAULT_PROVIDER;
|
||||
|
||||
/** @brief Size of the IO queue */
|
||||
std::optional<uint32_t> queueSizeIO = std::nullopt; // NOLINT(readability-redundant-member-init)
|
||||
|
||||
@@ -58,16 +58,14 @@ public:
|
||||
explicit Statement(std::string_view query, Args&&... args)
|
||||
: ManagedObject{cass_statement_new_n(query.data(), query.size(), sizeof...(args)), kDELETER}
|
||||
{
|
||||
// TODO: figure out how to set consistency level in config
|
||||
// NOTE: Keyspace doesn't support QUORUM at write level
|
||||
// cass_statement_set_consistency(*this, CASS_CONSISTENCY_LOCAL_QUORUM);
|
||||
cass_statement_set_consistency(*this, CASS_CONSISTENCY_LOCAL_QUORUM);
|
||||
cass_statement_set_is_idempotent(*this, cass_true);
|
||||
bind<Args...>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/* implicit */ Statement(CassStatement* ptr) : ManagedObject{ptr, kDELETER}
|
||||
{
|
||||
// cass_statement_set_consistency(*this, CASS_CONSISTENCY_LOCAL_QUORUM);
|
||||
cass_statement_set_consistency(*this, CASS_CONSISTENCY_LOCAL_QUORUM);
|
||||
cass_statement_set_is_idempotent(*this, cass_true);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "etl/NetworkValidatedLedgersInterface.hpp"
|
||||
#include "feed/SubscriptionManagerInterface.hpp"
|
||||
#include "rpc/JS.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
#include "util/Retry.hpp"
|
||||
#include "util/Spawn.hpp"
|
||||
#include "util/log/Logger.hpp"
|
||||
@@ -216,7 +215,7 @@ SubscriptionSource::handleMessage(std::string const& message)
|
||||
if (object.contains(JS(result))) {
|
||||
auto const& result = object.at(JS(result)).as_object();
|
||||
if (result.contains(JS(ledger_index)))
|
||||
ledgerIndex = util::integralValueAs<uint32_t>(result.at(JS(ledger_index)));
|
||||
ledgerIndex = result.at(JS(ledger_index)).as_int64();
|
||||
|
||||
if (result.contains(JS(validated_ledgers))) {
|
||||
auto validatedLedgers = boost::json::value_to<std::string>(result.at(JS(validated_ledgers)));
|
||||
@@ -228,7 +227,7 @@ SubscriptionSource::handleMessage(std::string const& message)
|
||||
LOG(log_.debug()) << "Received a message of type 'ledgerClosed' on ledger subscription stream. Message: "
|
||||
<< object;
|
||||
if (object.contains(JS(ledger_index))) {
|
||||
ledgerIndex = util::integralValueAs<uint32_t>(object.at(JS(ledger_index)));
|
||||
ledgerIndex = object.at(JS(ledger_index)).as_int64();
|
||||
}
|
||||
if (object.contains(JS(validated_ledgers))) {
|
||||
auto validatedLedgers = boost::json::value_to<std::string>(object.at(JS(validated_ledgers)));
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "rpc/JS.hpp"
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
#include "util/log/Logger.hpp"
|
||||
|
||||
#include <boost/asio/spawn.hpp>
|
||||
@@ -210,7 +209,6 @@ TransactionFeed::pub(
|
||||
|
||||
auto& txnPubobj = pubObj[txKey].as_object();
|
||||
rpc::insertDeliverMaxAlias(txnPubobj, version);
|
||||
rpc::insertMPTIssuanceID(txnPubobj, meta);
|
||||
|
||||
Json::Value nftJson;
|
||||
ripple::RPC::insertNFTSyntheticInJson(nftJson, tx, *meta);
|
||||
@@ -224,9 +222,8 @@ TransactionFeed::pub(
|
||||
auto const& metaObj = pubObj[JS(meta)];
|
||||
ASSERT(metaObj.is_object(), "meta must be an obj in rippled and clio");
|
||||
if (metaObj.as_object().contains("TransactionIndex") && metaObj.as_object().at("TransactionIndex").is_int64()) {
|
||||
if (auto const& ctid = rpc::encodeCTID(
|
||||
lgrInfo.seq, util::integralValueAs<uint16_t>(metaObj.as_object().at("TransactionIndex")), networkID
|
||||
);
|
||||
if (auto const& ctid =
|
||||
rpc::encodeCTID(lgrInfo.seq, metaObj.as_object().at("TransactionIndex").as_int64(), networkID);
|
||||
ctid)
|
||||
pubObj[JS(ctid)] = ctid.value();
|
||||
}
|
||||
|
||||
@@ -30,52 +30,15 @@
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace rpc {
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& stream, Status const& status)
|
||||
{
|
||||
std::visit(
|
||||
util::OverloadSet{
|
||||
[&stream, &status](RippledError err) {
|
||||
stream << "Code: " << static_cast<std::underlying_type_t<RippledError>>(err);
|
||||
if (!status.error.empty())
|
||||
stream << ", Error: " << status.error;
|
||||
if (!status.message.empty()) {
|
||||
stream << ", Message: " << status.message;
|
||||
} else {
|
||||
stream << ", Message: " << ripple::RPC::get_error_info(err).message;
|
||||
}
|
||||
},
|
||||
[&stream, &status](ClioError err) {
|
||||
stream << "Code: " << static_cast<std::underlying_type_t<ClioError>>(err);
|
||||
if (!status.error.empty())
|
||||
stream << ", Error: " << status.error;
|
||||
if (!status.message.empty()) {
|
||||
stream << ", Message: " << status.message;
|
||||
} else {
|
||||
stream << ", Message: " << getErrorInfo(err).message;
|
||||
}
|
||||
}
|
||||
},
|
||||
status.code
|
||||
);
|
||||
|
||||
if (status.extraInfo.has_value())
|
||||
stream << ", Extra Info: " << *status.extraInfo;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
WarningInfo const&
|
||||
getWarningInfo(WarningCode code)
|
||||
{
|
||||
|
||||
@@ -182,16 +182,6 @@ struct Status {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Custom output stream for Status
|
||||
*
|
||||
* @param stream The output stream
|
||||
* @param status The Status
|
||||
* @return The same ostream we were given
|
||||
*/
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& stream, Status const& status);
|
||||
};
|
||||
|
||||
/** @brief Warning codes that can be returned by clio. */
|
||||
|
||||
@@ -28,13 +28,11 @@
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/AccountUtils.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
#include "util/Profiler.hpp"
|
||||
#include "util/log/Logger.hpp"
|
||||
#include "web/Context.hpp"
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/format/format_fwd.hpp>
|
||||
#include <boost/format/free_funcs.hpp>
|
||||
@@ -174,7 +172,10 @@ canHaveDeliveredAmount(
|
||||
if (tt != ripple::ttPAYMENT && tt != ripple::ttCHECK_CASH && tt != ripple::ttACCOUNT_DELETE)
|
||||
return false;
|
||||
|
||||
return meta->getResultTER() == ripple::tesSUCCESS;
|
||||
if (meta->getResultTER() != ripple::tesSUCCESS)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<ripple::AccountID>
|
||||
@@ -258,7 +259,6 @@ toExpandedJson(
|
||||
auto metaJson = toJson(*meta);
|
||||
insertDeliveredAmount(metaJson, txn, meta, blobs.date);
|
||||
insertDeliverMaxAlias(txnJson, apiVersion);
|
||||
insertMPTIssuanceID(txnJson, meta);
|
||||
|
||||
if (nftEnabled == NFTokenjson::ENABLE) {
|
||||
Json::Value nftJson;
|
||||
@@ -317,66 +317,6 @@ insertDeliveredAmount(
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the delivered amount
|
||||
*
|
||||
* @param meta The metadata
|
||||
* @return The mpt_issuance_id or std::nullopt if not available
|
||||
*/
|
||||
static std::optional<ripple::uint192>
|
||||
getMPTIssuanceID(std::shared_ptr<ripple::TxMeta const> const& meta)
|
||||
{
|
||||
ripple::TxMeta const& transactionMeta = *meta;
|
||||
|
||||
for (ripple::STObject const& node : transactionMeta.getNodes()) {
|
||||
if (node.getFieldU16(ripple::sfLedgerEntryType) != ripple::ltMPTOKEN_ISSUANCE ||
|
||||
node.getFName() != ripple::sfCreatedNode)
|
||||
continue;
|
||||
|
||||
auto const& mptNode = node.peekAtField(ripple::sfNewFields).downcast<ripple::STObject>();
|
||||
return ripple::makeMptID(mptNode[ripple::sfSequence], mptNode[ripple::sfIssuer]);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if transaction has a new MPToken created
|
||||
*
|
||||
* @param txnJson The transaction Json
|
||||
* @param meta The metadata
|
||||
* @return true if the transaction can have a mpt_issuance_id
|
||||
*/
|
||||
static bool
|
||||
canHaveMPTIssuanceID(boost::json::object const& txnJson, std::shared_ptr<ripple::TxMeta const> const& meta)
|
||||
{
|
||||
if (txnJson.at(JS(TransactionType)).is_string() and
|
||||
not boost::iequals(txnJson.at(JS(TransactionType)).as_string(), JS(MPTokenIssuanceCreate)))
|
||||
return false;
|
||||
|
||||
if (meta->getResultTER() != ripple::tesSUCCESS)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
insertMPTIssuanceID(boost::json::object& txnJson, std::shared_ptr<ripple::TxMeta const> const& meta)
|
||||
{
|
||||
if (!canHaveMPTIssuanceID(txnJson, meta))
|
||||
return false;
|
||||
|
||||
if (txnJson.contains(JS(TransactionType)) && txnJson.at(JS(TransactionType)).is_string() and
|
||||
txnJson.at(JS(TransactionType)).as_string() == JS(MPTokenIssuanceCreate))
|
||||
return false;
|
||||
|
||||
auto const id = getMPTIssuanceID(meta);
|
||||
ASSERT(id.has_value(), "MPTIssuanceID must have value");
|
||||
txnJson[JS(mpt_issuance_id)] = ripple::to_string(*id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
insertDeliverMaxAlias(boost::json::object& txJson, std::uint32_t const apiVersion)
|
||||
{
|
||||
@@ -493,8 +433,8 @@ ledgerHeaderFromRequest(std::shared_ptr<data::BackendInterface const> const& bac
|
||||
} else {
|
||||
ledgerSequence = parseStringAsUInt(stringIndex);
|
||||
}
|
||||
} else if (indexValue.is_int64() or indexValue.is_uint64()) {
|
||||
ledgerSequence = util::integralValueAs<uint32_t>(indexValue);
|
||||
} else if (indexValue.is_int64()) {
|
||||
ledgerSequence = indexValue.as_int64();
|
||||
}
|
||||
} else {
|
||||
ledgerSequence = ctx.range.maxSequence;
|
||||
|
||||
@@ -199,18 +199,6 @@ insertDeliveredAmount(
|
||||
uint32_t date
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Add "mpt_issuance_id" into various MPTToken transaction json.
|
||||
* @note We exclude "mpt_issuance_id" for MPTokenIssuanceCreate only. The reason is because the mpt_issuance_id
|
||||
* is generated only after one submits MPTokenIssuanceCreate, so there’s no way to know what the id is. (rippled)
|
||||
*
|
||||
* @param txnJson The transaction Json object
|
||||
* @param meta The metadata object
|
||||
* @return true if the "mpt_issuance_id" is added to the txnJson JSON object
|
||||
*/
|
||||
bool
|
||||
insertMPTIssuanceID(boost::json::object& txnJson, std::shared_ptr<ripple::TxMeta const> const& meta);
|
||||
|
||||
/**
|
||||
* @brief Convert STBase object to JSON
|
||||
*
|
||||
|
||||
@@ -23,49 +23,10 @@
|
||||
#include <boost/json/object.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace rpc::validation {
|
||||
namespace impl {
|
||||
|
||||
template <std::unsigned_integral Expected>
|
||||
void
|
||||
clampAs(boost::json::value& value)
|
||||
{
|
||||
if (value.is_uint64()) {
|
||||
auto const valueUint = value.as_uint64();
|
||||
if (valueUint > static_cast<uint64_t>(std::numeric_limits<Expected>::max()))
|
||||
value = std::numeric_limits<Expected>::max();
|
||||
} else if (value.is_int64()) {
|
||||
auto const valueInt = value.as_int64();
|
||||
if (valueInt > static_cast<int64_t>(std::numeric_limits<Expected>::max()))
|
||||
value = std::numeric_limits<Expected>::max();
|
||||
}
|
||||
}
|
||||
|
||||
template <std::signed_integral Expected>
|
||||
void
|
||||
clampAs(boost::json::value& value)
|
||||
{
|
||||
if (value.is_uint64()) {
|
||||
auto const valueUint = value.as_uint64();
|
||||
if (valueUint > static_cast<uint64_t>(std::numeric_limits<Expected>::max()))
|
||||
value = std::numeric_limits<Expected>::max();
|
||||
} else if (value.is_int64()) {
|
||||
auto const valueInt = value.as_int64();
|
||||
if (valueInt > static_cast<int64_t>(std::numeric_limits<Expected>::max())) {
|
||||
value = std::numeric_limits<Expected>::max();
|
||||
} else if (valueInt < static_cast<int64_t>(std::numeric_limits<Expected>::min())) {
|
||||
value = std::numeric_limits<Expected>::min();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace impl
|
||||
|
||||
/**
|
||||
* @brief Check that the type is the same as what was expected.
|
||||
@@ -75,7 +36,7 @@ clampAs(boost::json::value& value)
|
||||
* @return true if convertible; false otherwise
|
||||
*/
|
||||
template <typename Expected>
|
||||
[[nodiscard]] bool
|
||||
[[nodiscard]] static bool
|
||||
checkType(boost::json::value const& value)
|
||||
{
|
||||
auto hasError = false;
|
||||
@@ -97,7 +58,7 @@ checkType(boost::json::value const& value)
|
||||
} else if constexpr (std::is_convertible_v<Expected, uint64_t> or std::is_convertible_v<Expected, int64_t>) {
|
||||
if (not value.is_int64() && not value.is_uint64())
|
||||
hasError = true;
|
||||
// if the type specified is unsigned, it should not be negative
|
||||
// specify the type is unsigened, it can not be negative
|
||||
if constexpr (std::is_unsigned_v<Expected>) {
|
||||
if (value.is_int64() and value.as_int64() < 0)
|
||||
hasError = true;
|
||||
@@ -107,28 +68,4 @@ checkType(boost::json::value const& value)
|
||||
return not hasError;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check that the type is the same as what was expected optionally clamping it into range.
|
||||
*
|
||||
* This is used to automatically clamp the value into the range available to the specified type. It is needed in
|
||||
* order to avoid Min, Max and other validators throw "not exact" error from Boost.Json library if the value does not
|
||||
* fit in the specified type.
|
||||
*
|
||||
* @tparam Expected The expected type that value should be convertible to
|
||||
* @param value The json value to check the type of
|
||||
* @return true if convertible; false otherwise
|
||||
*/
|
||||
template <typename Expected>
|
||||
[[nodiscard]] bool
|
||||
checkTypeAndClamp(boost::json::value& value)
|
||||
{
|
||||
if (not checkType<Expected>(value))
|
||||
return false; // fails basic type check
|
||||
|
||||
if constexpr (std::is_integral_v<Expected> and not std::is_same_v<Expected, bool>)
|
||||
impl::clampAs<Expected>(value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rpc::validation
|
||||
|
||||
@@ -142,21 +142,19 @@ template <typename... Types>
|
||||
struct Type final {
|
||||
/**
|
||||
* @brief Verify that the JSON value is (one) of specified type(s).
|
||||
* @note The value itself can only change for integral types and only if the value is outside of the range of the
|
||||
* expected integer type (see checkTypeAndClamp).
|
||||
*
|
||||
* @param value The JSON value representing the outer object
|
||||
* @param key The key used to retrieve the tested value from the outer object
|
||||
* @return `RippledError::rpcINVALID_PARAMS` if validation failed; otherwise no error is returned
|
||||
*/
|
||||
[[nodiscard]] MaybeError
|
||||
verify(boost::json::value& value, std::string_view key) const
|
||||
verify(boost::json::value const& value, std::string_view key) const
|
||||
{
|
||||
if (not value.is_object() or not value.as_object().contains(key))
|
||||
return {}; // ignore. If field is supposed to exist, let 'required' fail instead
|
||||
|
||||
auto& res = value.as_object().at(key);
|
||||
auto const convertible = (checkTypeAndClamp<Types>(res) || ...);
|
||||
auto const& res = value.as_object().at(key);
|
||||
auto const convertible = (checkType<Types>(res) || ...);
|
||||
|
||||
if (not convertible)
|
||||
return Error{Status{RippledError::rpcINVALID_PARAMS}};
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "rpc/common/impl/APIVersionParser.hpp"
|
||||
|
||||
#include "util/JsonUtils.hpp"
|
||||
#include "util/config/ObjectView.hpp"
|
||||
#include "util/log/Logger.hpp"
|
||||
|
||||
@@ -63,7 +62,7 @@ ProductionAPIVersionParser::parse(boost::json::object const& request) const
|
||||
if (!request.at("api_version").is_int64())
|
||||
return Error{"API version must be an integer"};
|
||||
|
||||
auto const version = util::integralValueAs<uint32_t>(request.at("api_version"));
|
||||
auto const version = request.at("api_version").as_int64();
|
||||
|
||||
if (version > maxVersion_)
|
||||
return Error{fmt::format("Requested API version is higher than maximum supported ({})", maxVersion_)};
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "rpc/common/Validators.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/array.hpp>
|
||||
#include <boost/json/conversion.hpp>
|
||||
@@ -318,7 +317,7 @@ tag_invoke(boost::json::value_to_tag<AMMInfoHandler::Input>, boost::json::value
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jv.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jv.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jv.at(JS(ledger_index))));
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/conversion.hpp>
|
||||
#include <boost/json/object.hpp>
|
||||
@@ -42,7 +41,6 @@
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol/tokens.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -143,7 +141,7 @@ tag_invoke(boost::json::value_to_tag<AccountChannelsHandler::Input>, boost::json
|
||||
input.account = boost::json::value_to<std::string>(jv.at(JS(account)));
|
||||
|
||||
if (jsonObject.contains(JS(limit)))
|
||||
input.limit = util::integralValueAs<uint32_t>(jv.at(JS(limit)));
|
||||
input.limit = jv.at(JS(limit)).as_int64();
|
||||
|
||||
if (jsonObject.contains(JS(marker)))
|
||||
input.marker = boost::json::value_to<std::string>(jv.at(JS(marker)));
|
||||
@@ -156,7 +154,7 @@ tag_invoke(boost::json::value_to_tag<AccountChannelsHandler::Input>, boost::json
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jv.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jv.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jv.at(JS(ledger_index))));
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/conversion.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
@@ -130,7 +129,7 @@ tag_invoke(boost::json::value_to_tag<AccountCurrenciesHandler::Input>, boost::js
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jv.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jv.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jv.at(JS(ledger_index))));
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "rpc/common/JsonBool.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/array.hpp>
|
||||
#include <boost/json/conversion.hpp>
|
||||
@@ -43,7 +42,6 @@
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
@@ -206,7 +204,7 @@ tag_invoke(boost::json::value_to_tag<AccountInfoHandler::Input>, boost::json::va
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jsonObject.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jsonObject.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jsonObject.at(JS(ledger_index))));
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/conversion.hpp>
|
||||
#include <boost/json/object.hpp>
|
||||
@@ -41,7 +40,6 @@
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -201,7 +199,7 @@ tag_invoke(boost::json::value_to_tag<AccountLinesHandler::Input>, boost::json::v
|
||||
|
||||
input.account = boost::json::value_to<std::string>(jv.at(JS(account)));
|
||||
if (jsonObject.contains(JS(limit)))
|
||||
input.limit = util::integralValueAs<uint32_t>(jv.at(JS(limit)));
|
||||
input.limit = jv.at(JS(limit)).as_int64();
|
||||
|
||||
if (jsonObject.contains(JS(marker)))
|
||||
input.marker = boost::json::value_to<std::string>(jv.at(JS(marker)));
|
||||
@@ -217,7 +215,7 @@ tag_invoke(boost::json::value_to_tag<AccountLinesHandler::Input>, boost::json::v
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jv.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jv.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jv.at(JS(ledger_index))));
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/conversion.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
@@ -159,14 +158,14 @@ tag_invoke(boost::json::value_to_tag<AccountNFTsHandler::Input>, boost::json::va
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jsonObject.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jsonObject.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jsonObject.at(JS(ledger_index))));
|
||||
}
|
||||
}
|
||||
|
||||
if (jsonObject.contains(JS(limit)))
|
||||
input.limit = util::integralValueAs<uint32_t>(jsonObject.at(JS(limit)));
|
||||
input.limit = jsonObject.at(JS(limit)).as_int64();
|
||||
|
||||
if (jsonObject.contains(JS(marker)))
|
||||
input.marker = boost::json::value_to<std::string>(jsonObject.at(JS(marker)));
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
#include "util/LedgerUtils.hpp"
|
||||
|
||||
#include <boost/json/array.hpp>
|
||||
@@ -39,7 +38,6 @@
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
@@ -155,7 +153,7 @@ tag_invoke(boost::json::value_to_tag<AccountObjectsHandler::Input>, boost::json:
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jv.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jv.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jv.at(JS(ledger_index))));
|
||||
}
|
||||
@@ -167,7 +165,7 @@ tag_invoke(boost::json::value_to_tag<AccountObjectsHandler::Input>, boost::json:
|
||||
}
|
||||
|
||||
if (jsonObject.contains(JS(limit)))
|
||||
input.limit = util::integralValueAs<uint32_t>(jv.at(JS(limit)));
|
||||
input.limit = jv.at(JS(limit)).as_int64();
|
||||
|
||||
if (jsonObject.contains(JS(marker)))
|
||||
input.marker = boost::json::value_to<std::string>(jv.at(JS(marker)));
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/conversion.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
@@ -41,7 +40,6 @@
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -171,14 +169,14 @@ tag_invoke(boost::json::value_to_tag<AccountOffersHandler::Input>, boost::json::
|
||||
}
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jsonObject.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jsonObject.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jsonObject.at(JS(ledger_index))));
|
||||
}
|
||||
}
|
||||
|
||||
if (jsonObject.contains(JS(limit)))
|
||||
input.limit = util::integralValueAs<uint32_t>(jsonObject.at(JS(limit)));
|
||||
input.limit = jsonObject.at(JS(limit)).as_int64();
|
||||
|
||||
if (jsonObject.contains(JS(marker)))
|
||||
input.marker = boost::json::value_to<std::string>(jsonObject.at(JS(marker)));
|
||||
|
||||
@@ -167,8 +167,7 @@ AccountTxHandler::process(AccountTxHandler::Input const& input, Context const& c
|
||||
if (auto const& etlState = etl_->getETLState(); etlState.has_value())
|
||||
networkID = etlState->networkID;
|
||||
|
||||
auto const txnIdx =
|
||||
util::integralValueAs<uint16_t>(obj[JS(meta)].as_object().at("TransactionIndex"));
|
||||
auto const txnIdx = obj[JS(meta)].as_object().at("TransactionIndex").as_int64();
|
||||
if (auto const& ctid = rpc::encodeCTID(txnPlusMeta.ledgerSequence, txnIdx, networkID); ctid)
|
||||
obj[txKey].as_object()[JS(ctid)] = ctid.value();
|
||||
}
|
||||
@@ -246,20 +245,18 @@ tag_invoke(boost::json::value_to_tag<AccountTxHandler::Input>, boost::json::valu
|
||||
|
||||
input.account = boost::json::value_to<std::string>(jsonObject.at(JS(account)));
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index_min)) &&
|
||||
util::integralValueAs<int32_t>(jsonObject.at(JS(ledger_index_min))) != -1)
|
||||
input.ledgerIndexMin = util::integralValueAs<int32_t>(jsonObject.at(JS(ledger_index_min)));
|
||||
if (jsonObject.contains(JS(ledger_index_min)) && jsonObject.at(JS(ledger_index_min)).as_int64() != -1)
|
||||
input.ledgerIndexMin = jsonObject.at(JS(ledger_index_min)).as_int64();
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index_max)) &&
|
||||
util::integralValueAs<int32_t>(jsonObject.at(JS(ledger_index_max))) != -1)
|
||||
input.ledgerIndexMax = util::integralValueAs<int32_t>(jsonObject.at(JS(ledger_index_max)));
|
||||
if (jsonObject.contains(JS(ledger_index_max)) && jsonObject.at(JS(ledger_index_max)).as_int64() != -1)
|
||||
input.ledgerIndexMax = jsonObject.at(JS(ledger_index_max)).as_int64();
|
||||
|
||||
if (jsonObject.contains(JS(ledger_hash)))
|
||||
input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash)));
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jsonObject.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jsonObject.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jsonObject.at(JS(ledger_index))));
|
||||
} else {
|
||||
@@ -275,12 +272,12 @@ tag_invoke(boost::json::value_to_tag<AccountTxHandler::Input>, boost::json::valu
|
||||
input.forward = boost::json::value_to<JsonBool>(jsonObject.at(JS(forward)));
|
||||
|
||||
if (jsonObject.contains(JS(limit)))
|
||||
input.limit = util::integralValueAs<uint32_t>(jsonObject.at(JS(limit)));
|
||||
input.limit = jsonObject.at(JS(limit)).as_int64();
|
||||
|
||||
if (jsonObject.contains(JS(marker))) {
|
||||
input.marker = AccountTxHandler::Marker{
|
||||
.ledger = util::integralValueAs<uint32_t>(jsonObject.at(JS(marker)).as_object().at(JS(ledger))),
|
||||
.seq = util::integralValueAs<uint32_t>(jsonObject.at(JS(marker)).as_object().at(JS(seq)))
|
||||
.ledger = jsonObject.at(JS(marker)).as_object().at(JS(ledger)).as_int64(),
|
||||
.seq = jsonObject.at(JS(marker)).as_object().at(JS(seq)).as_int64()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/conversion.hpp>
|
||||
#include <boost/json/object.hpp>
|
||||
@@ -36,7 +35,6 @@
|
||||
#include <xrpl/protocol/LedgerHeader.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -93,7 +91,7 @@ tag_invoke(boost::json::value_to_tag<BookChangesHandler::Input>, boost::json::va
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jv.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jv.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jv.at(JS(ledger_index))));
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/conversion.hpp>
|
||||
#include <boost/json/object.hpp>
|
||||
@@ -38,7 +37,6 @@
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace rpc {
|
||||
@@ -124,7 +122,7 @@ tag_invoke(boost::json::value_to_tag<BookOffersHandler::Input>, boost::json::val
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jv.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jv.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jv.at(JS(ledger_index))));
|
||||
}
|
||||
@@ -137,7 +135,7 @@ tag_invoke(boost::json::value_to_tag<BookOffersHandler::Input>, boost::json::val
|
||||
input.domain = boost::json::value_to<std::string>(jv.at(JS(domain)));
|
||||
|
||||
if (jsonObject.contains(JS(limit)))
|
||||
input.limit = util::integralValueAs<uint32_t>(jv.at(JS(limit)));
|
||||
input.limit = jv.at(JS(limit)).as_int64();
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/array.hpp>
|
||||
#include <boost/json/conversion.hpp>
|
||||
@@ -43,7 +42,6 @@
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -148,7 +146,7 @@ tag_invoke(boost::json::value_to_tag<DepositAuthorizedHandler::Input>, boost::js
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jv.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jv.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jv.at(JS(ledger_index))));
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "rpc/common/Validators.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/conversion.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
@@ -170,7 +169,7 @@ tag_invoke(boost::json::value_to_tag<FeatureHandler::Input>, boost::json::value
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jv.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jv.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jv.at(JS(ledger_index))));
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/array.hpp>
|
||||
#include <boost/json/conversion.hpp>
|
||||
@@ -251,7 +250,7 @@ tag_invoke(boost::json::value_to_tag<GatewayBalancesHandler::Input>, boost::json
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jv.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jv.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jv.at(JS(ledger_index))));
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/AccountUtils.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/bimap/bimap.hpp>
|
||||
@@ -265,7 +264,7 @@ tag_invoke(boost::json::value_to_tag<GetAggregatePriceHandler::Input>, boost::js
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jv.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jv.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jv.at(JS(ledger_index))));
|
||||
}
|
||||
@@ -285,10 +284,10 @@ tag_invoke(boost::json::value_to_tag<GetAggregatePriceHandler::Input>, boost::js
|
||||
input.quoteAsset = boost::json::value_to<std::string>(jv.at(JS(quote_asset)));
|
||||
|
||||
if (jsonObject.contains(JS(trim)))
|
||||
input.trim = util::integralValueAs<uint8_t>(jv.at(JS(trim)));
|
||||
input.trim = jv.at(JS(trim)).as_int64();
|
||||
|
||||
if (jsonObject.contains(JS(time_threshold)))
|
||||
input.timeThreshold = util::integralValueAs<uint32_t>(jv.at(JS(time_threshold)));
|
||||
input.timeThreshold = jv.at(JS(time_threshold)).as_int64();
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
@@ -131,8 +131,9 @@ public:
|
||||
!oracle.as_object().contains(JS(account)))
|
||||
return Error{Status{RippledError::rpcORACLE_MALFORMED}};
|
||||
|
||||
auto maybeError =
|
||||
validation::Type<std::uint32_t, std::string>{}.verify(oracle, JS(oracle_document_id));
|
||||
auto maybeError = validation::Type<std::uint32_t, std::string>{}.verify(
|
||||
oracle.as_object(), JS(oracle_document_id)
|
||||
);
|
||||
if (!maybeError)
|
||||
return maybeError;
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/array.hpp>
|
||||
#include <boost/json/conversion.hpp>
|
||||
@@ -43,7 +42,6 @@
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -211,7 +209,7 @@ tag_invoke(boost::json::value_to_tag<LedgerHandler::Input>, boost::json::value c
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jv.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jv.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jv.at(JS(ledger_index))));
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
#include "util/LedgerUtils.hpp"
|
||||
#include "util/log/Logger.hpp"
|
||||
|
||||
@@ -45,7 +44,6 @@
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@@ -194,7 +192,7 @@ tag_invoke(boost::json::value_to_tag<LedgerDataHandler::Input>, boost::json::val
|
||||
}
|
||||
|
||||
if (jsonObject.contains(JS(limit)))
|
||||
input.limit = util::integralValueAs<uint32_t>(jsonObject.at(JS(limit)));
|
||||
input.limit = jsonObject.at(JS(limit)).as_int64();
|
||||
|
||||
if (jsonObject.contains("out_of_order"))
|
||||
input.outOfOrder = jsonObject.at("out_of_order").as_bool();
|
||||
@@ -203,7 +201,7 @@ tag_invoke(boost::json::value_to_tag<LedgerDataHandler::Input>, boost::json::val
|
||||
if (jsonObject.at(JS(marker)).is_string()) {
|
||||
input.marker = ripple::uint256{boost::json::value_to<std::string>(jsonObject.at(JS(marker))).data()};
|
||||
} else {
|
||||
input.diffMarker = util::integralValueAs<uint32_t>(jsonObject.at(JS(marker)));
|
||||
input.diffMarker = jsonObject.at(JS(marker)).as_int64();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,7 +210,7 @@ tag_invoke(boost::json::value_to_tag<LedgerDataHandler::Input>, boost::json::val
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jsonObject.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jsonObject.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jsonObject.at(JS(ledger_index))));
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/AccountUtils.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/conversion.hpp>
|
||||
#include <boost/json/object.hpp>
|
||||
@@ -95,7 +94,7 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input const& input, Context cons
|
||||
auto const id = util::parseBase58Wrapper<ripple::AccountID>(
|
||||
boost::json::value_to<std::string>(input.escrow->at(JS(owner)))
|
||||
);
|
||||
key = ripple::keylet::escrow(*id, util::integralValueAs<uint32_t>(input.escrow->at(JS(seq)))).key;
|
||||
key = ripple::keylet::escrow(*id, input.escrow->at(JS(seq)).as_int64()).key;
|
||||
} else if (input.depositPreauth) {
|
||||
auto const owner = util::parseBase58Wrapper<ripple::AccountID>(
|
||||
boost::json::value_to<std::string>(input.depositPreauth->at(JS(owner)))
|
||||
@@ -129,7 +128,7 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input const& input, Context cons
|
||||
boost::json::value_to<std::string>(input.ticket->at(JS(account)))
|
||||
);
|
||||
|
||||
key = ripple::getTicketIndex(*id, util::integralValueAs<uint32_t>(input.ticket->at(JS(ticket_seq))));
|
||||
key = ripple::getTicketIndex(*id, input.ticket->at(JS(ticket_seq)).as_int64());
|
||||
} else if (input.amm) {
|
||||
auto const getIssuerFromJson = [](auto const& assetJson) {
|
||||
// the field check has been done in validator
|
||||
@@ -183,12 +182,12 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input const& input, Context cons
|
||||
auto const account = ripple::parseBase58<ripple::AccountID>(
|
||||
boost::json::value_to<std::string>(input.permissionedDomain->at(JS(account)))
|
||||
);
|
||||
auto const seq = util::integralValueAs<uint32_t>(input.permissionedDomain->at(JS(seq)));
|
||||
auto const seq = input.permissionedDomain->at(JS(seq)).as_int64();
|
||||
key = ripple::keylet::permissionedDomain(*account, seq).key;
|
||||
} else if (input.vault) {
|
||||
auto const account =
|
||||
ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(input.vault->at(JS(owner))));
|
||||
auto const seq = util::integralValueAs<uint32_t>(input.vault->at(JS(seq)));
|
||||
auto const seq = input.vault->at(JS(seq)).as_int64();
|
||||
key = ripple::keylet::vault(*account, seq).key;
|
||||
} else if (input.delegate) {
|
||||
auto const account =
|
||||
@@ -305,7 +304,7 @@ tag_invoke(boost::json::value_to_tag<LedgerEntryHandler::Input>, boost::json::va
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jv.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jv.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jv.at(JS(ledger_index))));
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/array.hpp>
|
||||
#include <boost/json/conversion.hpp>
|
||||
@@ -39,7 +38,6 @@
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
@@ -126,14 +124,14 @@ tag_invoke(boost::json::value_to_tag<MPTHoldersHandler::Input>, boost::json::val
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jsonObject.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jsonObject.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(jsonObject.at(JS(ledger_index)).as_string().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (jsonObject.contains(JS(limit)))
|
||||
input.limit = util::integralValueAs<uint32_t>(jsonObject.at(JS(limit)));
|
||||
input.limit = jsonObject.at(JS(limit)).as_int64();
|
||||
|
||||
if (jsonObject.contains(JS(marker)))
|
||||
input.marker = jsonObject.at(JS(marker)).as_string().c_str();
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
#include "util/Profiler.hpp"
|
||||
#include "util/log/Logger.hpp"
|
||||
|
||||
@@ -204,20 +203,18 @@ tag_invoke(boost::json::value_to_tag<NFTHistoryHandler::Input>, boost::json::val
|
||||
|
||||
input.nftID = boost::json::value_to<std::string>(jsonObject.at(JS(nft_id)));
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index_min)) &&
|
||||
util::integralValueAs<int32_t>(jsonObject.at(JS(ledger_index_min))) != -1)
|
||||
input.ledgerIndexMin = util::integralValueAs<uint32_t>(jsonObject.at(JS(ledger_index_min)));
|
||||
if (jsonObject.contains(JS(ledger_index_min)) && jsonObject.at(JS(ledger_index_min)).as_int64() != -1)
|
||||
input.ledgerIndexMin = jsonObject.at(JS(ledger_index_min)).as_int64();
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index_max)) &&
|
||||
util::integralValueAs<int32_t>(jsonObject.at(JS(ledger_index_max))) != -1)
|
||||
input.ledgerIndexMax = util::integralValueAs<uint32_t>(jsonObject.at(JS(ledger_index_max)));
|
||||
if (jsonObject.contains(JS(ledger_index_max)) && jsonObject.at(JS(ledger_index_max)).as_int64() != -1)
|
||||
input.ledgerIndexMax = jsonObject.at(JS(ledger_index_max)).as_int64();
|
||||
|
||||
if (jsonObject.contains(JS(ledger_hash)))
|
||||
input.ledgerHash = boost::json::value_to<std::string>(jsonObject.at(JS(ledger_hash)));
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jsonObject.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jsonObject.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jsonObject.at(JS(ledger_index))));
|
||||
}
|
||||
@@ -230,12 +227,12 @@ tag_invoke(boost::json::value_to_tag<NFTHistoryHandler::Input>, boost::json::val
|
||||
input.forward = jsonObject.at(JS(forward)).as_bool();
|
||||
|
||||
if (jsonObject.contains(JS(limit)))
|
||||
input.limit = util::integralValueAs<uint32_t>(jsonObject.at(JS(limit)));
|
||||
input.limit = jsonObject.at(JS(limit)).as_int64();
|
||||
|
||||
if (jsonObject.contains(JS(marker))) {
|
||||
input.marker = NFTHistoryHandler::Marker{
|
||||
.ledger = util::integralValueAs<uint32_t>(jsonObject.at(JS(marker)).as_object().at(JS(ledger))),
|
||||
.seq = util::integralValueAs<uint32_t>(jsonObject.at(JS(marker)).as_object().at(JS(seq)))
|
||||
.ledger = jsonObject.at(JS(marker)).as_object().at(JS(ledger)).as_int64(),
|
||||
.seq = jsonObject.at(JS(marker)).as_object().at(JS(seq)).as_int64()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/conversion.hpp>
|
||||
#include <boost/json/object.hpp>
|
||||
@@ -37,7 +36,6 @@
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol/nft.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
using namespace ripple;
|
||||
@@ -118,7 +116,7 @@ tag_invoke(boost::json::value_to_tag<NFTInfoHandler::Input>, boost::json::value
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jsonObject.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jsonObject.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jsonObject.at(JS(ledger_index))));
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/json/conversion.hpp>
|
||||
@@ -196,7 +195,7 @@ tag_invoke(boost::json::value_to_tag<NFTOffersHandlerBase::Input>, boost::json::
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jsonObject.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jsonObject.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jsonObject.at(JS(ledger_index))));
|
||||
}
|
||||
@@ -206,7 +205,7 @@ tag_invoke(boost::json::value_to_tag<NFTOffersHandlerBase::Input>, boost::json::
|
||||
input.marker = boost::json::value_to<std::string>(jsonObject.at(JS(marker)));
|
||||
|
||||
if (jsonObject.contains(JS(limit)))
|
||||
input.limit = util::integralValueAs<uint32_t>(jsonObject.at(JS(limit)));
|
||||
input.limit = jsonObject.at(JS(limit)).as_int64();
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/conversion.hpp>
|
||||
#include <boost/json/object.hpp>
|
||||
@@ -38,7 +37,6 @@
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol/nft.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
@@ -138,17 +136,17 @@ tag_invoke(boost::json::value_to_tag<NFTsByIssuerHandler::Input>, boost::json::v
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jsonObject.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jsonObject.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jsonObject.at(JS(ledger_index))));
|
||||
}
|
||||
}
|
||||
|
||||
if (jsonObject.contains(JS(limit)))
|
||||
input.limit = util::integralValueAs<uint32_t>(jsonObject.at(JS(limit)));
|
||||
input.limit = jsonObject.at(JS(limit)).as_int64();
|
||||
|
||||
if (jsonObject.contains(JS(nft_taxon)))
|
||||
input.nftTaxon = util::integralValueAs<uint32_t>(jsonObject.at(JS(nft_taxon)));
|
||||
input.nftTaxon = jsonObject.at(JS(nft_taxon)).as_int64();
|
||||
|
||||
if (jsonObject.contains(JS(marker)))
|
||||
input.marker = boost::json::value_to<std::string>(jsonObject.at(JS(marker)));
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "rpc/common/JsonBool.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/array.hpp>
|
||||
#include <boost/json/conversion.hpp>
|
||||
@@ -188,7 +187,7 @@ tag_invoke(boost::json::value_to_tag<NoRippleCheckHandler::Input>, boost::json::
|
||||
input.roleGateway = jsonObject.at(JS(role)).as_string() == "gateway";
|
||||
|
||||
if (jsonObject.contains(JS(limit)))
|
||||
input.limit = util::integralValueAs<uint32_t>(jsonObject.at(JS(limit)));
|
||||
input.limit = jsonObject.at(JS(limit)).as_int64();
|
||||
|
||||
if (jsonObject.contains(JS(transactions)))
|
||||
input.transactions = boost::json::value_to<JsonBool>(jsonObject.at(JS(transactions)));
|
||||
@@ -198,7 +197,7 @@ tag_invoke(boost::json::value_to_tag<NoRippleCheckHandler::Input>, boost::json::
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jsonObject.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jsonObject.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jsonObject.at(JS(ledger_index))));
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/conversion.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
@@ -34,7 +33,6 @@
|
||||
#include <xrpl/basics/strHex.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
@@ -112,7 +110,7 @@ tag_invoke(boost::json::value_to_tag<TransactionEntryHandler::Input>, boost::jso
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (!jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jv.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jv.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(boost::json::value_to<std::string>(jv.at(JS(ledger_index))));
|
||||
}
|
||||
|
||||
@@ -332,10 +332,10 @@ private:
|
||||
input.binary = boost::json::value_to<JsonBool>(jsonObject.at(JS(binary)));
|
||||
|
||||
if (jsonObject.contains(JS(min_ledger)))
|
||||
input.minLedger = util::integralValueAs<uint32_t>(jv.at(JS(min_ledger)));
|
||||
input.minLedger = jv.at(JS(min_ledger)).as_int64();
|
||||
|
||||
if (jsonObject.contains(JS(max_ledger)))
|
||||
input.maxLedger = util::integralValueAs<uint32_t>(jv.at(JS(max_ledger)));
|
||||
input.maxLedger = jv.at(JS(max_ledger)).as_int64();
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/conversion.hpp>
|
||||
#include <boost/json/object.hpp>
|
||||
@@ -172,14 +171,14 @@ tag_invoke(boost::json::value_to_tag<VaultInfoHandler::Input>, boost::json::valu
|
||||
input.owner = jsonObject.at(JS(owner)).as_string();
|
||||
|
||||
if (jsonObject.contains(JS(seq)))
|
||||
input.tnxSequence = util::integralValueAs<uint32_t>(jsonObject.at(JS(seq)));
|
||||
input.tnxSequence = static_cast<uint32_t>(jsonObject.at(JS(seq)).as_int64());
|
||||
|
||||
if (jsonObject.contains(JS(vault_id)))
|
||||
input.vaultID = jsonObject.at(JS(vault_id)).as_string();
|
||||
|
||||
if (jsonObject.contains(JS(ledger_index))) {
|
||||
if (not jsonObject.at(JS(ledger_index)).is_string()) {
|
||||
input.ledgerIndex = util::integralValueAs<uint32_t>(jsonObject.at(JS(ledger_index)));
|
||||
input.ledgerIndex = jsonObject.at(JS(ledger_index)).as_int64();
|
||||
} else if (jsonObject.at(JS(ledger_index)).as_string() != "validated") {
|
||||
input.ledgerIndex = std::stoi(jsonObject.at(JS(ledger_index)).as_string().c_str());
|
||||
}
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <concepts>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
@@ -88,26 +86,4 @@ removeSecret(boost::json::object const& object)
|
||||
return newObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Detects the type of number stored in value and casts it back to the requested Type.
|
||||
* @note This conversion can possibly cause wrapping around or UB. Use with caution.
|
||||
*
|
||||
* @tparam Type The type to cast to
|
||||
* @param value The JSON value to cast
|
||||
* @return Value casted to the requested type
|
||||
* @throws logic_error if the underlying number is neither int64 nor uint64
|
||||
*/
|
||||
template <std::integral Type>
|
||||
Type
|
||||
integralValueAs(boost::json::value const& value)
|
||||
{
|
||||
if (value.is_uint64())
|
||||
return static_cast<Type>(value.as_uint64());
|
||||
|
||||
if (value.is_int64())
|
||||
return static_cast<Type>(value.as_int64());
|
||||
|
||||
throw std::logic_error("Value neither uint64 nor int64");
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <utility>
|
||||
|
||||
namespace util {
|
||||
|
||||
namespace impl {
|
||||
|
||||
class SignalsHandlerStatic {
|
||||
|
||||
@@ -37,10 +37,9 @@
|
||||
#include <optional>
|
||||
|
||||
namespace util {
|
||||
|
||||
namespace impl {
|
||||
|
||||
class SignalsHandlerStatic;
|
||||
|
||||
} // namespace impl
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "data/LedgerCacheInterface.hpp"
|
||||
#include "util/Taggable.hpp"
|
||||
#include "web/AdminVerificationStrategy.hpp"
|
||||
#include "web/PlainWsSession.hpp"
|
||||
@@ -70,7 +69,6 @@ public:
|
||||
* @param tagFactory A factory that is used to generate tags to track requests and sessions
|
||||
* @param dosGuard The denial of service guard to use
|
||||
* @param handler The server handler to use
|
||||
* @param cache The ledger cache to use
|
||||
* @param buffer Buffer with initial data received from the peer
|
||||
* @param maxWsSendingQueueSize The maximum size of the sending queue for websocket
|
||||
*/
|
||||
@@ -82,7 +80,6 @@ public:
|
||||
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
|
||||
std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
|
||||
std::shared_ptr<HandlerType> const& handler,
|
||||
std::reference_wrapper<data::LedgerCacheInterface const> cache,
|
||||
boost::beast::flat_buffer buffer,
|
||||
std::uint32_t maxWsSendingQueueSize
|
||||
)
|
||||
@@ -93,7 +90,6 @@ public:
|
||||
std::move(proxyIpResolver),
|
||||
dosGuard,
|
||||
handler,
|
||||
cache,
|
||||
std::move(buffer)
|
||||
)
|
||||
, stream_(std::move(socket))
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "data/LedgerCacheInterface.hpp"
|
||||
#include "util/Taggable.hpp"
|
||||
#include "util/log/Logger.hpp"
|
||||
#include "web/AdminVerificationStrategy.hpp"
|
||||
@@ -86,7 +85,6 @@ class Detector : public std::enable_shared_from_this<Detector<PlainSessionType,
|
||||
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory_;
|
||||
std::reference_wrapper<dosguard::DOSGuardInterface> const dosGuard_;
|
||||
std::shared_ptr<HandlerType> const handler_;
|
||||
std::reference_wrapper<data::LedgerCacheInterface const> cache_;
|
||||
boost::beast::flat_buffer buffer_;
|
||||
std::shared_ptr<AdminVerificationStrategy> const adminVerification_;
|
||||
std::uint32_t maxWsSendingQueueSize_;
|
||||
@@ -101,7 +99,6 @@ public:
|
||||
* @param tagFactory A factory that is used to generate tags to track requests and sessions
|
||||
* @param dosGuard The denial of service guard to use
|
||||
* @param handler The server handler to use
|
||||
* @param cache The ledger cache to use
|
||||
* @param adminVerification The admin verification strategy to use
|
||||
* @param maxWsSendingQueueSize The maximum size of the sending queue for websocket
|
||||
* @param proxyIpResolver The client ip resolver if a request was forwarded by a proxy
|
||||
@@ -112,7 +109,6 @@ public:
|
||||
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
|
||||
std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
|
||||
std::shared_ptr<HandlerType> handler,
|
||||
std::reference_wrapper<data::LedgerCacheInterface const> cache,
|
||||
std::shared_ptr<AdminVerificationStrategy> adminVerification,
|
||||
std::uint32_t maxWsSendingQueueSize,
|
||||
std::shared_ptr<ProxyIpResolver> proxyIpResolver
|
||||
@@ -122,7 +118,6 @@ public:
|
||||
, tagFactory_(std::cref(tagFactory))
|
||||
, dosGuard_(dosGuard)
|
||||
, handler_(std::move(handler))
|
||||
, cache_(cache)
|
||||
, adminVerification_(std::move(adminVerification))
|
||||
, maxWsSendingQueueSize_(maxWsSendingQueueSize)
|
||||
, proxyIpResolver_(std::move(proxyIpResolver))
|
||||
@@ -184,7 +179,6 @@ public:
|
||||
tagFactory_,
|
||||
dosGuard_,
|
||||
handler_,
|
||||
cache_,
|
||||
std::move(buffer_),
|
||||
maxWsSendingQueueSize_
|
||||
)
|
||||
@@ -200,7 +194,6 @@ public:
|
||||
tagFactory_,
|
||||
dosGuard_,
|
||||
handler_,
|
||||
cache_,
|
||||
std::move(buffer_),
|
||||
maxWsSendingQueueSize_
|
||||
)
|
||||
@@ -230,7 +223,6 @@ class Server : public std::enable_shared_from_this<Server<PlainSessionType, SslS
|
||||
util::TagDecoratorFactory tagFactory_;
|
||||
std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard_;
|
||||
std::shared_ptr<HandlerType> handler_;
|
||||
std::reference_wrapper<data::LedgerCacheInterface const> cache_;
|
||||
tcp::acceptor acceptor_;
|
||||
std::shared_ptr<AdminVerificationStrategy> adminVerification_;
|
||||
std::uint32_t maxWsSendingQueueSize_;
|
||||
@@ -246,7 +238,6 @@ public:
|
||||
* @param tagFactory A factory that is used to generate tags to track requests and sessions
|
||||
* @param dosGuard The denial of service guard to use
|
||||
* @param handler The server handler to use
|
||||
* @param cache The ledger cache to use
|
||||
* @param adminVerification The admin verification strategy to use
|
||||
* @param maxWsSendingQueueSize The maximum size of the sending queue for websocket
|
||||
* @param proxyIpResolver The client ip resolver if a request was forwarded by a proxy
|
||||
@@ -258,7 +249,6 @@ public:
|
||||
util::TagDecoratorFactory tagFactory,
|
||||
dosguard::DOSGuardInterface& dosGuard,
|
||||
std::shared_ptr<HandlerType> handler,
|
||||
std::reference_wrapper<data::LedgerCacheInterface const> cache,
|
||||
std::shared_ptr<AdminVerificationStrategy> adminVerification,
|
||||
std::uint32_t maxWsSendingQueueSize,
|
||||
ProxyIpResolver proxyIpResolver
|
||||
@@ -268,7 +258,6 @@ public:
|
||||
, tagFactory_(tagFactory)
|
||||
, dosGuard_(std::ref(dosGuard))
|
||||
, handler_(std::move(handler))
|
||||
, cache_(cache)
|
||||
, acceptor_(boost::asio::make_strand(ioc))
|
||||
, adminVerification_(std::move(adminVerification))
|
||||
, maxWsSendingQueueSize_(maxWsSendingQueueSize)
|
||||
@@ -331,7 +320,6 @@ private:
|
||||
std::cref(tagFactory_),
|
||||
dosGuard_,
|
||||
handler_,
|
||||
cache_,
|
||||
adminVerification_,
|
||||
maxWsSendingQueueSize_,
|
||||
proxyIpResolver_
|
||||
@@ -355,7 +343,6 @@ using HttpServer = Server<HttpSession, SslHttpSession, HandlerType>;
|
||||
* @param ioc The server will run under this io_context
|
||||
* @param dosGuard The dos guard to protect the server
|
||||
* @param handler The handler to process the request
|
||||
* @param cache The ledger cache to use
|
||||
* @return The server instance
|
||||
*/
|
||||
template <typename HandlerType>
|
||||
@@ -364,8 +351,7 @@ makeHttpServer(
|
||||
util::config::ClioConfigDefinition const& config,
|
||||
boost::asio::io_context& ioc,
|
||||
dosguard::DOSGuardInterface& dosGuard,
|
||||
std::shared_ptr<HandlerType> const& handler,
|
||||
std::reference_wrapper<data::LedgerCacheInterface const> cache
|
||||
std::shared_ptr<HandlerType> const& handler
|
||||
)
|
||||
{
|
||||
static util::Logger const log{"WebServer"}; // NOLINT(readability-identifier-naming)
|
||||
@@ -399,7 +385,6 @@ makeHttpServer(
|
||||
util::TagDecoratorFactory(config),
|
||||
dosGuard,
|
||||
handler,
|
||||
cache,
|
||||
std::move(expectedAdminVerification).value(),
|
||||
maxWsSendingQueueSize,
|
||||
std::move(proxyIpResolver)
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "data/LedgerCacheInterface.hpp"
|
||||
#include "util/Taggable.hpp"
|
||||
#include "web/AdminVerificationStrategy.hpp"
|
||||
#include "web/ProxyIpResolver.hpp"
|
||||
@@ -77,7 +76,6 @@ public:
|
||||
* @param tagFactory A factory that is used to generate tags to track requests and sessions
|
||||
* @param dosGuard The denial of service guard to use
|
||||
* @param handler The server handler to use
|
||||
* @param cache The ledger cache to use
|
||||
* @param buffer Buffer with initial data received from the peer
|
||||
* @param maxWsSendingQueueSize The maximum size of the sending queue for websocket
|
||||
*/
|
||||
@@ -90,7 +88,6 @@ public:
|
||||
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
|
||||
std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
|
||||
std::shared_ptr<HandlerType> const& handler,
|
||||
std::reference_wrapper<data::LedgerCacheInterface const> cache,
|
||||
boost::beast::flat_buffer buffer,
|
||||
std::uint32_t maxWsSendingQueueSize
|
||||
)
|
||||
@@ -101,7 +98,6 @@ public:
|
||||
std::move(proxyIpResolver),
|
||||
dosGuard,
|
||||
handler,
|
||||
cache,
|
||||
std::move(buffer)
|
||||
)
|
||||
, stream_(std::move(socket), ctx)
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "data/LedgerCacheInterface.hpp"
|
||||
#include "rpc/Errors.hpp"
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/Taggable.hpp"
|
||||
@@ -72,22 +71,6 @@ static constexpr auto kHEALTH_CHECK_HTML = R"html(
|
||||
</html>
|
||||
)html";
|
||||
|
||||
static constexpr auto kCACHE_CHECK_LOADED_HTML = R"html(
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title>Cache state</title></head>
|
||||
<body><h1>Cache state</h1><p>Cache is fully loaded</p></body>
|
||||
</html>
|
||||
)html";
|
||||
|
||||
static constexpr auto kCACHE_CHECK_NOT_LOADED_HTML = R"html(
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title>Cache state</title></head>
|
||||
<body><h1>Cache state</h1><p>Cache is not yet loaded</p></body>
|
||||
</html>
|
||||
)html";
|
||||
|
||||
using tcp = boost::asio::ip::tcp;
|
||||
|
||||
/**
|
||||
@@ -145,7 +128,6 @@ protected:
|
||||
http::request<http::string_body> req_;
|
||||
std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard_;
|
||||
std::shared_ptr<HandlerType> const handler_;
|
||||
std::reference_wrapper<data::LedgerCacheInterface const> cache_;
|
||||
util::Logger log_{"WebServer"};
|
||||
util::Logger perfLog_{"Performance"};
|
||||
|
||||
@@ -187,7 +169,6 @@ public:
|
||||
std::shared_ptr<ProxyIpResolver> proxyIpResolver,
|
||||
std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
|
||||
std::shared_ptr<HandlerType> handler,
|
||||
std::reference_wrapper<data::LedgerCacheInterface const> cache,
|
||||
boost::beast::flat_buffer buffer
|
||||
)
|
||||
: ConnectionBase(tagFactory, ip)
|
||||
@@ -197,7 +178,6 @@ public:
|
||||
, buffer_(std::move(buffer))
|
||||
, dosGuard_(dosGuard)
|
||||
, handler_(std::move(handler))
|
||||
, cache_(cache)
|
||||
{
|
||||
LOG(perfLog_.debug()) << tag() << "http session created";
|
||||
dosGuard_.get().increment(ip);
|
||||
@@ -242,13 +222,6 @@ public:
|
||||
if (req_.method() == http::verb::get and req_.target() == "/health")
|
||||
return sender_(httpResponse(http::status::ok, "text/html", kHEALTH_CHECK_HTML));
|
||||
|
||||
if (req_.method() == http::verb::get and req_.target() == "/cache_state") {
|
||||
if (cache_.get().isFull())
|
||||
return sender_(httpResponse(http::status::ok, "text/html", kCACHE_CHECK_LOADED_HTML));
|
||||
|
||||
return sender_(httpResponse(http::status::service_unavailable, "text/html", kCACHE_CHECK_NOT_LOADED_HTML));
|
||||
}
|
||||
|
||||
if (auto resolvedIp = proxyIpResolver_->resolveClientIp(clientIp_, req_); resolvedIp != clientIp_) {
|
||||
LOG(log_.info()) << tag() << "Detected a forwarded request from proxy. Proxy ip: " << clientIp_
|
||||
<< ". Resolved client ip: " << resolvedIp;
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include <openssl/tls1.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
@@ -1528,66 +1528,6 @@ createMPTIssuanceCreateTxWithMetadata(std::string_view accountId, uint32_t fee,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ripple::STObject
|
||||
createMPTokenAuthorizeTx(
|
||||
std::string_view accountId,
|
||||
ripple::uint192 const& mptIssuanceID,
|
||||
uint32_t fee,
|
||||
uint32_t seq,
|
||||
std::optional<std::string_view> holder,
|
||||
std::optional<std::uint32_t> flags
|
||||
)
|
||||
{
|
||||
ripple::STObject tx(ripple::sfTransaction);
|
||||
tx.setFieldU16(ripple::sfTransactionType, ripple::ttMPTOKEN_AUTHORIZE);
|
||||
tx.setAccountID(ripple::sfAccount, getAccountIdWithString(accountId));
|
||||
tx[ripple::sfMPTokenIssuanceID] = mptIssuanceID;
|
||||
tx.setFieldAmount(ripple::sfFee, ripple::STAmount(fee, false));
|
||||
tx.setFieldU32(ripple::sfSequence, seq);
|
||||
tx.setFieldVL(ripple::sfSigningPubKey, kSLICE);
|
||||
|
||||
if (holder)
|
||||
tx.setAccountID(ripple::sfHolder, getAccountIdWithString(*holder));
|
||||
if (flags)
|
||||
tx.setFieldU32(ripple::sfFlags, *flags);
|
||||
|
||||
return tx;
|
||||
}
|
||||
|
||||
data::TransactionAndMetadata
|
||||
createMPTokenAuthorizeTxWithMetadata(
|
||||
std::string_view accountId,
|
||||
ripple::uint192 const& mptIssuanceID,
|
||||
uint32_t fee,
|
||||
uint32_t seq
|
||||
)
|
||||
{
|
||||
ripple::STObject const tx = createMPTokenAuthorizeTx(accountId, mptIssuanceID, fee, seq);
|
||||
|
||||
ripple::STObject metaObj(ripple::sfTransactionMetaData);
|
||||
metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS);
|
||||
metaObj.setFieldU32(ripple::sfTransactionIndex, 0);
|
||||
|
||||
ripple::STObject finalFields(ripple::sfFinalFields);
|
||||
finalFields.setFieldU16(ripple::sfLedgerEntryType, ripple::ltMPTOKEN);
|
||||
finalFields[ripple::sfMPTokenIssuanceID] = mptIssuanceID;
|
||||
finalFields.setFieldU64(ripple::sfMPTAmount, 0);
|
||||
|
||||
ripple::STObject modifiedNode(ripple::sfModifiedNode);
|
||||
modifiedNode.setFieldU16(ripple::sfLedgerEntryType, ripple::ltMPTOKEN);
|
||||
modifiedNode.setFieldH256(ripple::sfLedgerIndex, ripple::uint256{});
|
||||
modifiedNode.emplace_back(std::move(finalFields));
|
||||
|
||||
ripple::STArray affectedNodes(ripple::sfAffectedNodes);
|
||||
affectedNodes.push_back(std::move(modifiedNode));
|
||||
metaObj.setFieldArray(ripple::sfAffectedNodes, affectedNodes);
|
||||
|
||||
data::TransactionAndMetadata ret;
|
||||
ret.transaction = tx.getSerializer().peekData();
|
||||
ret.metadata = metaObj.getSerializer().peekData();
|
||||
return ret;
|
||||
}
|
||||
|
||||
ripple::STObject
|
||||
createPermissionedDomainObject(
|
||||
std::string_view accountId,
|
||||
|
||||
@@ -462,26 +462,6 @@ createMPTIssuanceCreateTx(std::string_view accountId, uint32_t fee, uint32_t seq
|
||||
[[nodiscard]] data::TransactionAndMetadata
|
||||
createMPTIssuanceCreateTxWithMetadata(std::string_view accountId, uint32_t fee, uint32_t seq);
|
||||
|
||||
[[nodiscard]]
|
||||
ripple::STObject
|
||||
createMPTokenAuthorizeTx(
|
||||
std::string_view accountId,
|
||||
ripple::uint192 const& mptIssuanceID,
|
||||
uint32_t fee,
|
||||
uint32_t seq,
|
||||
std::optional<std::string_view> holder = std::nullopt,
|
||||
std::optional<std::uint32_t> flags = std::nullopt
|
||||
);
|
||||
|
||||
[[nodiscard]]
|
||||
data::TransactionAndMetadata
|
||||
createMPTokenAuthorizeTxWithMetadata(
|
||||
std::string_view accountId,
|
||||
ripple::uint192 const& mptIssuanceID,
|
||||
uint32_t fee,
|
||||
uint32_t seq
|
||||
);
|
||||
|
||||
[[nodiscard]] ripple::STObject
|
||||
createPermissionedDomainObject(
|
||||
std::string_view accountId,
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include "util/LoggerFixtures.hpp"
|
||||
#include "util/TerminationHandler.hpp"
|
||||
|
||||
#include <TestGlobals.hpp>
|
||||
@@ -34,8 +33,6 @@ main(int argc, char* argv[])
|
||||
{
|
||||
util::setTerminationHandler();
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
LoggerFixture::init();
|
||||
|
||||
TestGlobals::instance().parse(argc, argv);
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "data/cassandra/Handle.hpp"
|
||||
#include "data/cassandra/Types.hpp"
|
||||
#include "util/LoggerFixtures.hpp"
|
||||
|
||||
#include <TestGlobals.hpp>
|
||||
#include <cassandra.h>
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "migration/impl/MigrationManagerBase.hpp"
|
||||
#include "migration/impl/MigratorsRegister.hpp"
|
||||
#include "util/CassandraDBHelper.hpp"
|
||||
#include "util/LoggerFixtures.hpp"
|
||||
#include "util/MockPrometheus.hpp"
|
||||
#include "util/config/ConfigConstraints.hpp"
|
||||
#include "util/config/ConfigDefinition.hpp"
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include "util/CassandraDBHelper.hpp"
|
||||
|
||||
#include "data/cassandra/Handle.hpp"
|
||||
#include "data/cassandra/Types.hpp"
|
||||
#include "data/cassandra/impl/Result.hpp"
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "data/cassandra/Handle.hpp"
|
||||
#include "data/cassandra/Types.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@@ -20,13 +20,8 @@
|
||||
#include "util/JsonUtils.hpp"
|
||||
|
||||
#include <boost/json/parse.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
|
||||
TEST(JsonUtils, RemoveSecrets)
|
||||
{
|
||||
auto json = boost::json::parse(R"JSON({
|
||||
@@ -65,26 +60,3 @@ TEST(JsonUtils, RemoveSecrets)
|
||||
EXPECT_EQ(json2.at("seed_hex").as_string(), "*");
|
||||
EXPECT_EQ(json2.at("passphrase").as_string(), "*");
|
||||
}
|
||||
|
||||
TEST(JsonUtils, integralValueAs)
|
||||
{
|
||||
auto const expectedResultUint64 = static_cast<uint64_t>(std::numeric_limits<int32_t>::max()) + 1u;
|
||||
auto const uint64Json = boost::json::value(expectedResultUint64);
|
||||
EXPECT_EQ(util::integralValueAs<int32_t>(uint64Json), std::numeric_limits<int32_t>::min());
|
||||
EXPECT_EQ(util::integralValueAs<uint32_t>(uint64Json), expectedResultUint64);
|
||||
EXPECT_EQ(util::integralValueAs<int64_t>(uint64Json), expectedResultUint64);
|
||||
EXPECT_EQ(util::integralValueAs<uint64_t>(uint64Json), expectedResultUint64);
|
||||
|
||||
auto const expectedResultInt64 = static_cast<int64_t>(std::numeric_limits<int32_t>::max()) + 1u;
|
||||
auto const int64Json = boost::json::value(expectedResultInt64);
|
||||
EXPECT_EQ(util::integralValueAs<int32_t>(int64Json), std::numeric_limits<int32_t>::min());
|
||||
EXPECT_EQ(util::integralValueAs<uint32_t>(int64Json), expectedResultInt64);
|
||||
EXPECT_EQ(util::integralValueAs<int64_t>(int64Json), expectedResultInt64);
|
||||
EXPECT_EQ(util::integralValueAs<uint64_t>(int64Json), expectedResultInt64);
|
||||
|
||||
auto const doubleJson = boost::json::value(3.14);
|
||||
EXPECT_THROW(util::integralValueAs<int>(doubleJson), std::logic_error);
|
||||
|
||||
auto const stringJson = boost::json::value("not a number");
|
||||
EXPECT_THROW(util::integralValueAs<int>(stringJson), std::logic_error);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
//==============================================================================
|
||||
#include "app/Stopper.hpp"
|
||||
#include "util/AsioContextTestFixture.hpp"
|
||||
#include "util/LoggerFixtures.hpp"
|
||||
#include "util/MockBackend.hpp"
|
||||
#include "util/MockETLService.hpp"
|
||||
#include "util/MockLoadBalancer.hpp"
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "app/WebHandlers.hpp"
|
||||
#include "rpc/Errors.hpp"
|
||||
#include "util/AsioContextTestFixture.hpp"
|
||||
#include "util/MockLedgerCache.hpp"
|
||||
#include "util/LoggerFixtures.hpp"
|
||||
#include "util/MockPrometheus.hpp"
|
||||
#include "util/Taggable.hpp"
|
||||
#include "util/config/ConfigDefinition.hpp"
|
||||
@@ -150,32 +150,6 @@ TEST_F(HealthCheckHandlerTests, Call)
|
||||
});
|
||||
}
|
||||
|
||||
struct CacheStateHandlerTests : SyncAsioContextTest, WebHandlersTest {
|
||||
web::ng::Request request{http::request<http::string_body>{http::verb::get, "/", 11}};
|
||||
MockLedgerCache cache;
|
||||
CacheStateHandler cacheStateHandler{cache};
|
||||
};
|
||||
|
||||
TEST_F(CacheStateHandlerTests, CallWithCacheLoaded)
|
||||
{
|
||||
EXPECT_CALL(cache, isFull()).WillRepeatedly(testing::Return(true));
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
auto response = cacheStateHandler(request, connectionMock, nullptr, yield);
|
||||
auto const httpResponse = std::move(response).intoHttpResponse();
|
||||
EXPECT_EQ(httpResponse.result(), boost::beast::http::status::ok);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(CacheStateHandlerTests, CallWithoutCacheLoaded)
|
||||
{
|
||||
EXPECT_CALL(cache, isFull()).WillRepeatedly(testing::Return(false));
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
auto response = cacheStateHandler(request, connectionMock, nullptr, yield);
|
||||
auto const httpResponse = std::move(response).intoHttpResponse();
|
||||
EXPECT_EQ(httpResponse.result(), boost::beast::http::status::service_unavailable);
|
||||
});
|
||||
}
|
||||
|
||||
struct RequestHandlerTest : SyncAsioContextTest, WebHandlersTest {
|
||||
AdminVerificationStrategyStrictMockPtr adminVerifier{
|
||||
std::make_shared<testing::StrictMock<AdminVerificationStrategyMock>>()
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
//==============================================================================
|
||||
|
||||
#include "data/LedgerCache.hpp"
|
||||
#include "util/LoggerFixtures.hpp"
|
||||
#include "util/MockPrometheus.hpp"
|
||||
#include "util/prometheus/Bool.hpp"
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user