Compare commits
98 commits
super-mari
...
v0
| Author | SHA1 | Date | |
|---|---|---|---|
| 9ebf88d8eb | |||
| f678bcc929 | |||
| e8f5ff3c24 | |||
| d63fe663de | |||
| de20212d1e | |||
| d10e0cb596 | |||
| d39758d748 | |||
| 97d0a1f553 | |||
| 9f2ab87f6a | |||
| 0df281cd61 | |||
| 0f89601f2e | |||
| 28911c801a | |||
| 96f0e6c652 | |||
| 43e526c834 | |||
| b486e5e590 | |||
| 7565501c19 | |||
| 5a69d2acf5 | |||
| e06ea4c0cb | |||
| 9d3a25fd95 | |||
| e6ec245b87 | |||
| 5972833136 | |||
| 28670c09ef | |||
| 6daf271cbd | |||
| c8626564d4 | |||
| b9bfac8c70 | |||
| 3b933501f0 | |||
| c19f859bcc | |||
| 747e37409f | |||
| 48ace5124b | |||
| 2342bcd4ea | |||
| 367d7dfc69 | |||
| 92ba5b1a75 | |||
| 225b28aa84 | |||
| 62e68d7abb | |||
| 24095fb80c | |||
| 368bc2e45a | |||
| 340275fd0a | |||
| cccb5e9877 | |||
| f48e2d232b | |||
| 74061ef3b5 | |||
| 6a70df89ed | |||
| cbd175229e | |||
| 65c3642439 | |||
| 678ec565a5 | |||
| 4136a76803 | |||
| b2693d0eea | |||
| d715fe27e4 | |||
| 8b53d0f650 | |||
| 2cbac0b1e5 | |||
| b467dca528 | |||
| c53df3176a | |||
| e63ad228c1 | |||
| c828d3b973 | |||
| ed84a47a2e | |||
| c5822ae632 | |||
| e7044e21e9 | |||
| 12ce2e59c0 | |||
| ce14f2676e | |||
| a17e914849 | |||
| dd1926fd3a | |||
| dc6307cfcf | |||
| 9275f3b09f | |||
| 29a8b015bd | |||
| f8e887496f | |||
| 547ae0d76d | |||
| 0b777d00ae | |||
| 6ff9b33966 | |||
| e129f9c3b3 | |||
| ebefd8f955 | |||
| f870853630 | |||
| be6aabb4eb | |||
| 50864770fe | |||
| 18c8ec77dd | |||
| 2a2dbd5ff1 | |||
| 7f27ad0a3c | |||
| a88f1898a5 | |||
| 70ced21e59 | |||
| 6e47874c1f | |||
| f3718ed680 | |||
| 40c3f65650 | |||
| 020319fe4b | |||
| 289f1a438f | |||
| cc7c3ff4b3 | |||
| f27051ff2c | |||
| 479e4fa6c0 | |||
| f5d4c56ce0 | |||
| 7f79a53f8c | |||
| 8c9703f1a9 | |||
| 53d71957b5 | |||
| b7a9455e55 | |||
| 21e3227347 | |||
| b4ad3d9c6f | |||
| cd794cef37 | |||
| 242054e333 | |||
| 6d3f4bd8a2 | |||
| 1befcf11a2 | |||
| 5379d99c29 | |||
| 50f6d496d7 |
87 changed files with 3768 additions and 2927 deletions
|
|
@ -1,17 +1,15 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
export EDITION=$1
|
export EDITION=$1
|
||||||
export BA="--build-arg EDITION=$1"
|
source /etc/environment
|
||||||
|
: "${RNEX_CONTAINER_PLATFORM:=podman}"
|
||||||
|
|
||||||
# podman build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/dev-container:latest" --target=dev-container .
|
for TARGET in node-holder proxy-secure proxy-insecure backend-auth backend-secure; do
|
||||||
# podman push "$CI_REGISTRY_IMAGE/$EDITION/dev-container:latest"
|
$RNEX_CONTAINER_PLATFORM build \
|
||||||
podman build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/node-holder:$CI_COMMIT_SHORT_SHA" --target=node-holder .
|
--network=host \
|
||||||
podman build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/proxy-secure:$CI_COMMIT_SHORT_SHA" --target=proxy-secure .
|
--build-arg EDITION="$EDITION" \
|
||||||
podman build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/proxy-insecure:$CI_COMMIT_SHORT_SHA" --target=proxy-insecure .
|
--build-arg DATABASE_URL="$DATABASE_URL" \
|
||||||
podman build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/backend-auth:$CI_COMMIT_SHORT_SHA" --target=backend-auth .
|
-t "$CI_REGISTRY_IMAGE/$EDITION/$TARGET:$CI_COMMIT_SHORT_SHA" \
|
||||||
podman build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/backend-secure:$CI_COMMIT_SHORT_SHA" --target=backend-secure .
|
--target="$TARGET" .
|
||||||
podman push "$CI_REGISTRY_IMAGE/$EDITION/node-holder:$CI_COMMIT_SHORT_SHA"
|
|
||||||
podman push "$CI_REGISTRY_IMAGE/$EDITION/proxy-secure:$CI_COMMIT_SHORT_SHA"
|
$RNEX_CONTAINER_PLATFORM push "$CI_REGISTRY_IMAGE/$EDITION/$TARGET:$CI_COMMIT_SHORT_SHA"
|
||||||
podman push "$CI_REGISTRY_IMAGE/$EDITION/proxy-insecure:$CI_COMMIT_SHORT_SHA"
|
done
|
||||||
podman push "$CI_REGISTRY_IMAGE/$EDITION/backend-auth:$CI_COMMIT_SHORT_SHA"
|
|
||||||
podman push "$CI_REGISTRY_IMAGE/$EDITION/backend-secure:$CI_COMMIT_SHORT_SHA"
|
|
||||||
|
|
@ -7,4 +7,6 @@ CONTRIBUTING.md
|
||||||
README.md
|
README.md
|
||||||
.gitignore
|
.gitignore
|
||||||
LICENSE
|
LICENSE
|
||||||
.devcontainer.json
|
.devcontainer.json
|
||||||
|
.ci-scripts/make-edition.sh
|
||||||
|
.forgejo/workflows/build.yml
|
||||||
314
.forgejo/workflows/build.yml
Normal file
314
.forgejo/workflows/build.yml
Normal file
|
|
@ -0,0 +1,314 @@
|
||||||
|
name: Build and Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["**"]
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
env:
|
||||||
|
DOCKER_TLS_CERTDIR: /certs
|
||||||
|
IMAGE_TAG: ${{ github.sha }}
|
||||||
|
SHORT_SHA: ${{ github.sha }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
mario-tennis:
|
||||||
|
runs-on: debian-trixie
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Cache container storage
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/var/lib/containers/storage
|
||||||
|
/run/containers/storage
|
||||||
|
~/.local/share/containers/storage
|
||||||
|
key: image-cache
|
||||||
|
|
||||||
|
- name: Login to registry
|
||||||
|
run: docker login -u ${{ secrets.PACKAGE_USER }} -p ${{ secrets.PACKAGE_PWD }} git.spbr.net
|
||||||
|
|
||||||
|
- name: Set short SHA
|
||||||
|
run: echo "SHORT_SHA=${GITHUB_SHA::6}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build MTUS tetris edition
|
||||||
|
env:
|
||||||
|
CI_REGISTRY_IMAGE: git.spbr.net/spacebar/rust-nex
|
||||||
|
CI_COMMIT_SHORT_SHA: ${{ env.SHORT_SHA }}
|
||||||
|
run: ./.ci-scripts/make-edition.sh mario-tennis
|
||||||
|
|
||||||
|
wii-sports-club:
|
||||||
|
runs-on: debian-trixie
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Cache container storage
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/var/lib/containers/storage
|
||||||
|
/run/containers/storage
|
||||||
|
~/.local/share/containers/storage
|
||||||
|
key: image-cache
|
||||||
|
|
||||||
|
- name: Login to registry
|
||||||
|
run: docker login -u ${{ secrets.PACKAGE_USER }} -p ${{ secrets.PACKAGE_PWD }} git.spbr.net
|
||||||
|
|
||||||
|
- name: Set short SHA
|
||||||
|
run: echo "SHORT_SHA=${GITHUB_SHA::6}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build Wii Sports Club edition
|
||||||
|
env:
|
||||||
|
CI_REGISTRY_IMAGE: git.spbr.net/spacebar/rust-nex
|
||||||
|
CI_COMMIT_SHORT_SHA: ${{ env.SHORT_SHA }}
|
||||||
|
run: ./.ci-scripts/make-edition.sh wii-sports-club
|
||||||
|
|
||||||
|
puyopuyo:
|
||||||
|
runs-on: debian-trixie
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Cache container storage
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/var/lib/containers/storage
|
||||||
|
/run/containers/storage
|
||||||
|
~/.local/share/containers/storage
|
||||||
|
key: image-cache
|
||||||
|
|
||||||
|
- name: Login to registry
|
||||||
|
run: docker login -u ${{ secrets.PACKAGE_USER }} -p ${{ secrets.PACKAGE_PWD }} git.spbr.net
|
||||||
|
|
||||||
|
- name: Set short SHA
|
||||||
|
run: echo "SHORT_SHA=${GITHUB_SHA::6}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build puyo puyo tetris edition
|
||||||
|
env:
|
||||||
|
CI_REGISTRY_IMAGE: git.spbr.net/spacebar/rust-nex
|
||||||
|
CI_COMMIT_SHORT_SHA: ${{ env.SHORT_SHA }}
|
||||||
|
run: ./.ci-scripts/make-edition.sh puyopuyo
|
||||||
|
|
||||||
|
minecraft-wiiu:
|
||||||
|
runs-on: debian-trixie
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Cache container storage
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/var/lib/containers/storage
|
||||||
|
/run/containers/storage
|
||||||
|
~/.local/share/containers/storage
|
||||||
|
key: image-cache
|
||||||
|
|
||||||
|
- name: Login to registry
|
||||||
|
run: docker login -u ${{ secrets.PACKAGE_USER }} -p ${{ secrets.PACKAGE_PWD }} git.spbr.net
|
||||||
|
|
||||||
|
- name: Set short SHA
|
||||||
|
run: echo "SHORT_SHA=${GITHUB_SHA::6}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build Minecraft Wii U edition
|
||||||
|
env:
|
||||||
|
CI_REGISTRY_IMAGE: git.spbr.net/spacebar/rust-nex
|
||||||
|
CI_COMMIT_SHORT_SHA: ${{ env.SHORT_SHA }}
|
||||||
|
run: ./.ci-scripts/make-edition.sh minecraft-wiiu
|
||||||
|
|
||||||
|
splatoon-testfire:
|
||||||
|
runs-on: debian-trixie
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Cache container storage
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/var/lib/containers/storage
|
||||||
|
/run/containers/storage
|
||||||
|
~/.local/share/containers/storage
|
||||||
|
key: image-cache
|
||||||
|
|
||||||
|
- name: Login to registry
|
||||||
|
run: docker login -u ${{ secrets.PACKAGE_USER }} -p ${{ secrets.PACKAGE_PWD }} git.spbr.net
|
||||||
|
|
||||||
|
- name: Set short SHA
|
||||||
|
run: echo "SHORT_SHA=${GITHUB_SHA::6}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build Splatoon Testfire edition
|
||||||
|
env:
|
||||||
|
CI_REGISTRY_IMAGE: git.spbr.net/spacebar/rust-nex
|
||||||
|
CI_COMMIT_SHORT_SHA: ${{ env.SHORT_SHA }}
|
||||||
|
run: ./.ci-scripts/make-edition.sh splatoon-testfire
|
||||||
|
|
||||||
|
fast-racing-neo:
|
||||||
|
runs-on: debian-trixie
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Cache container storage
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/var/lib/containers/storage
|
||||||
|
/run/containers/storage
|
||||||
|
~/.local/share/containers/storage
|
||||||
|
key: image-cache
|
||||||
|
|
||||||
|
- name: Login to registry
|
||||||
|
run: docker login -u ${{ secrets.PACKAGE_USER }} -p ${{ secrets.PACKAGE_PWD }} git.spbr.net
|
||||||
|
|
||||||
|
- name: Set short SHA
|
||||||
|
run: echo "SHORT_SHA=${GITHUB_SHA::6}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build Fast Racing NEO edition
|
||||||
|
env:
|
||||||
|
CI_REGISTRY_IMAGE: git.spbr.net/spacebar/rust-nex
|
||||||
|
CI_COMMIT_SHORT_SHA: ${{ env.SHORT_SHA }}
|
||||||
|
run: ./.ci-scripts/make-edition.sh fast-racing-neo
|
||||||
|
|
||||||
|
wii-u-chat:
|
||||||
|
runs-on: debian-trixie
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Cache container storage
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/var/lib/containers/storage
|
||||||
|
/run/containers/storage
|
||||||
|
~/.local/share/containers/storage
|
||||||
|
key: image-cache
|
||||||
|
|
||||||
|
- name: Login to registry
|
||||||
|
run: docker login -u ${{ secrets.PACKAGE_USER }} -p ${{ secrets.PACKAGE_PWD }} git.spbr.net
|
||||||
|
|
||||||
|
- name: Set short SHA
|
||||||
|
run: echo "SHORT_SHA=${GITHUB_SHA::6}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build Wii U Chat edition
|
||||||
|
env:
|
||||||
|
CI_REGISTRY_IMAGE: git.spbr.net/spacebar/rust-nex
|
||||||
|
CI_COMMIT_SHORT_SHA: ${{ env.SHORT_SHA }}
|
||||||
|
run: ./.ci-scripts/make-edition.sh wii-u-chat
|
||||||
|
|
||||||
|
splatoon:
|
||||||
|
runs-on: debian-trixie
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Cache container storage
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/var/lib/containers/storage
|
||||||
|
/run/containers/storage
|
||||||
|
~/.local/share/containers/storage
|
||||||
|
key: image-cache
|
||||||
|
|
||||||
|
- name: Login to registry
|
||||||
|
run: docker login -u ${{ secrets.PACKAGE_USER }} -p ${{ secrets.PACKAGE_PWD }} git.spbr.net
|
||||||
|
|
||||||
|
- name: Set short SHA
|
||||||
|
run: echo "SHORT_SHA=${GITHUB_SHA::6}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build Splatoon edition
|
||||||
|
env:
|
||||||
|
CI_REGISTRY_IMAGE: git.spbr.net/spacebar/rust-nex
|
||||||
|
CI_COMMIT_SHORT_SHA: ${{ env.SHORT_SHA }}
|
||||||
|
run: ./.ci-scripts/make-edition.sh splatoon
|
||||||
|
|
||||||
|
friends:
|
||||||
|
runs-on: debian-trixie
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Cache container storage
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/var/lib/containers/storage
|
||||||
|
/run/containers/storage
|
||||||
|
~/.local/share/containers/storage
|
||||||
|
key: image-cache
|
||||||
|
|
||||||
|
- name: Set short SHA
|
||||||
|
run: echo "SHORT_SHA=${GITHUB_SHA::6}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Login to registry
|
||||||
|
run: podman login -u ${{ secrets.PACKAGE_USER }} -p ${{ secrets.PACKAGE_PWD }} git.spbr.net
|
||||||
|
|
||||||
|
- name: Build Friends edition
|
||||||
|
env:
|
||||||
|
CI_REGISTRY_IMAGE: git.spbr.net/spacebar/rust-nex
|
||||||
|
CI_COMMIT_SHORT_SHA: ${{ env.SHORT_SHA }}
|
||||||
|
DATABASE_URL: ${{ secrets.DATABASE_FRIENDS }}
|
||||||
|
run: ./.ci-scripts/make-edition.sh friends
|
||||||
|
|
||||||
|
super-mario-maker:
|
||||||
|
runs-on: debian-trixie
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Cache container storage
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/var/lib/containers/storage
|
||||||
|
/run/containers/storage
|
||||||
|
~/.local/share/containers/storage
|
||||||
|
key: image-cache
|
||||||
|
|
||||||
|
- name: Set short SHA
|
||||||
|
run: echo "SHORT_SHA=${GITHUB_SHA::6}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Login to registry
|
||||||
|
run: podman login -u ${{ secrets.PACKAGE_USER }} -p ${{ secrets.PACKAGE_PWD }} git.spbr.net
|
||||||
|
|
||||||
|
- name: Build Super Mario Maker edition
|
||||||
|
env:
|
||||||
|
CI_REGISTRY_IMAGE: git.spbr.net/spacebar/rust-nex
|
||||||
|
CI_COMMIT_SHORT_SHA: ${{ env.SHORT_SHA }}
|
||||||
|
DATABASE_URL: ${{ secrets.DATABASE_SMM }}
|
||||||
|
run: ./.ci-scripts/make-edition.sh super-mario-maker
|
||||||
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"rust-analyzer.cargo.features": [
|
||||||
|
"friends"
|
||||||
|
]
|
||||||
|
}
|
||||||
888
Cargo.lock
generated
888
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
53
Dockerfile
53
Dockerfile
|
|
@ -1,42 +1,57 @@
|
||||||
FROM rust:alpine AS build-container
|
# syntax=docker/dockerfile:1
|
||||||
|
FROM rust:alpine AS chef
|
||||||
RUN apk add --no-cache protobuf-dev git musl-dev lld openssl-dev openssl-libs-static yq bash
|
RUN apk add --no-cache musl-dev lld g++ make
|
||||||
|
RUN cargo install cargo-chef
|
||||||
FROM build-container AS builder
|
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
FROM chef AS planner
|
||||||
COPY . .
|
COPY . .
|
||||||
|
RUN cargo chef prepare --recipe-path recipe.json
|
||||||
|
|
||||||
|
FROM chef AS builder
|
||||||
|
RUN apk add --no-cache protobuf-dev git openssl-dev openssl-libs-static bash yq
|
||||||
|
|
||||||
|
COPY --from=planner /app/recipe.json recipe.json
|
||||||
ARG EDITION
|
ARG EDITION
|
||||||
|
ARG DATABASE_URL
|
||||||
|
|
||||||
RUN git submodule update --init --recursive
|
RUN --mount=type=cache,target=/usr/local/cargo/registry \
|
||||||
|
--mount=type=cache,target=/app/target \
|
||||||
|
cargo chef cook --release --recipe-path recipe.json --target x86_64-unknown-linux-musl && \
|
||||||
|
cargo chef cook --tests --target x86_64-unknown-linux-musl --recipe-path recipe.json
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
RUN --mount=type=cache,target=/usr/local/cargo/registry \
|
||||||
|
--mount=type=cache,target=/app/target \
|
||||||
|
./test-edition.sh && ./build-edition.sh && \
|
||||||
|
mkdir -p /app/dist && \
|
||||||
|
cp /app/target/x86_64-unknown-linux-musl/release/edge_node_holder_server /app/dist/ && \
|
||||||
|
cp /app/target/x86_64-unknown-linux-musl/release/proxy_insecure /app/dist/ && \
|
||||||
|
cp /app/target/x86_64-unknown-linux-musl/release/proxy_secure /app/dist/ && \
|
||||||
|
cp /app/target/x86_64-unknown-linux-musl/release/backend_server_insecure /app/dist/ && \
|
||||||
|
cp /app/target/x86_64-unknown-linux-musl/release/backend_server_secure /app/dist/
|
||||||
|
|
||||||
RUN ./test-edition.sh
|
|
||||||
RUN ./build-edition.sh
|
|
||||||
|
|
||||||
FROM scratch AS node-holder
|
FROM scratch AS node-holder
|
||||||
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/edge_node_holder_server /edge_node_holder_server
|
COPY --from=builder /app/dist/edge_node_holder_server /edge_node_holder_server
|
||||||
ENTRYPOINT ["/edge_node_holder_server"]
|
ENTRYPOINT ["/edge_node_holder_server"]
|
||||||
|
|
||||||
|
|
||||||
FROM scratch AS proxy-insecure
|
FROM scratch AS proxy-insecure
|
||||||
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/proxy_insecure /proxy_insecure
|
COPY --from=builder /app/dist/proxy_insecure /proxy_insecure
|
||||||
ENTRYPOINT ["/proxy_insecure"]
|
ENTRYPOINT ["/proxy_insecure"]
|
||||||
|
|
||||||
FROM scratch AS proxy-secure
|
FROM scratch AS proxy-secure
|
||||||
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/proxy_secure /proxy_secure
|
COPY --from=builder /app/dist/proxy_secure /proxy_secure
|
||||||
ENTRYPOINT ["/proxy_secure"]
|
ENTRYPOINT ["/proxy_secure"]
|
||||||
|
|
||||||
|
|
||||||
FROM scratch AS backend-auth
|
FROM scratch AS backend-auth
|
||||||
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/backend_server_insecure /backend_server_insecure
|
COPY --from=builder /app/dist/backend_server_insecure /backend_server_insecure
|
||||||
ENTRYPOINT ["/backend_server_insecure"]
|
ENTRYPOINT ["/backend_server_insecure"]
|
||||||
|
|
||||||
FROM scratch AS backend-secure
|
FROM scratch AS backend-secure
|
||||||
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/backend_server_secure /backend_server_secure
|
COPY --from=builder /app/dist/backend_server_secure /backend_server_secure
|
||||||
ENTRYPOINT ["/backend_server_secure"]
|
ENTRYPOINT ["/backend_server_secure"]
|
||||||
|
|
||||||
# make sure the final output container is the dev container so that we can use it from the devcontainer.json
|
FROM chef AS dev-container
|
||||||
FROM build-container AS dev-container
|
RUN apk add --no-cache openjdk21-jdk gcompat git bash protobuf-dev
|
||||||
RUN apk add openjdk21-jdk gcompat
|
COPY --from=builder /app/dist/* /usr/local/bin/
|
||||||
22
README.md
22
README.md
|
|
@ -1,20 +1,16 @@
|
||||||
# Splatoon NEX Server in Rust
|
# Rust NEX monorepo
|
||||||
|
|
||||||
|
This repo contains the code for all game servers using RNEX.
|
||||||
|
|
||||||
## Credits:
|
## Credits:
|
||||||
- Pretendo team for the rest of the Servers and Reverse engineering efforts
|
- Pretendo team for their reverse engineering efforts
|
||||||
- Kinnay for his huge work on reversing nex servers and documentation(https://github.com/Kinnay/NintendoClients/)
|
- Kinnay for his huge work on reversing nex servers and documentation(https://github.com/Kinnay/NintendoClients/)
|
||||||
- Splatfestival testing team for helping us test our messes of code
|
- Splatfestival testing team for helping us test our messes of code
|
||||||
- The SPFN team(Bloxer, Ceantix and RusticMaple)
|
- The SPFN team(RusticMaple, BloxerHD, Ceantix, RedBinder0526)
|
||||||
|
|
||||||
This nex implementation was not created and is not intended to compete with pretendo,
|
This NEX implementation was not created to rival Pretendo, we don't want any bad blood between anyone.
|
||||||
we wholeheartedly support pretendo.
|
|
||||||
This project would never have been possible without their reverse engineering efforts.
|
This project would never have been possible without their reverse engineering efforts.
|
||||||
As such if you want to respect the Authors wishes(Maple(Me) is pretty much the sole author of Rust-Nex), do not
|
As such if you want to respect the Authors wishes, do not use it if you mean any harm to Pretendo. (harm falls under e.g. using this software while also sabotaging pretendo) If you do show intent to harm them you will be blocked from ever contributing and will be refused support.
|
||||||
use it if you mean any harm to pretendo. If you do show intent to harm them you will be blocked from ever contributing
|
|
||||||
and will be refused support, as such please also refrain from asking for support if you have been blocked by pretendo.
|
|
||||||
|
|
||||||
|
We felt like this needed to be said as there are far too many Pretendo copycats who blatantly copy their code and use their reversal efforts with no credits in sight in an attempt to harm them for some grudge or stupid reason.
|
||||||
I felt like this needed to be said as there are far too many pretendo copycats who blatantly copy their code and use
|
We feel that by working together and not against each other we can reach a better and healthier future for the community, health of developers and numerous more reasons.
|
||||||
their reversal efforts with no credits in sight in an attempt to harm them for some grudge or stupid reason.
|
|
||||||
I feel that by working together and not against each other we can reach a better and healthier future for the community,
|
|
||||||
health of developers and numerous more reasons.
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,15 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
if [ -z ${EDITION+x} ]; then
|
if [ -z ${EDITION+x} ]; then
|
||||||
EDITION=$1
|
EDITION=$1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# comma seperated list of features for the specified version
|
# comma seperated list of features for the specified version
|
||||||
source ./buildscripts/common.sh
|
source ./buildscripts/common.sh
|
||||||
|
echo building $EDITION
|
||||||
echo FEATURES:
|
echo FEATURES:
|
||||||
echo $EDITION_FEATURES
|
echo $EDITION_FEATURES
|
||||||
echo ENV SETTINGS:
|
|
||||||
env
|
|
||||||
|
|
||||||
OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo build --release --features "$EDITION_FEATURES" --target x86_64-unknown-linux-musl
|
OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo build --release --features "$EDITION_FEATURES" --target x86_64-unknown-linux-musl
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
TMP_FEATURES_TRAILINGCOMMA=$(yq ea ".$EDITION.features" editions.yaml | sed 's/- //g' | tr '\n' ',')
|
TMP_FEATURES_TRAILINGCOMMA=$(yq ea ".$EDITION.features" editions.yaml | sed 's/- //g' | tr '\n' ',')
|
||||||
|
echo "tmpfeatures: $TMP_FEATURES_TRAILINGCOMMA"
|
||||||
export EDITION_FEATURES=${TMP_FEATURES_TRAILINGCOMMA::-1}
|
export EDITION_FEATURES=${TMP_FEATURES_TRAILINGCOMMA::-1}
|
||||||
SETTINGS=$(yq ea ".$EDITION.settings" editions.yaml | yq 'keys[]')
|
SETTINGS=$(yq ea ".$EDITION.settings" editions.yaml | yq 'keys[]')
|
||||||
IFS=$'\n'
|
IFS=$'\n'
|
||||||
|
|
|
||||||
14
buildscripts/pre-commit
Executable file
14
buildscripts/pre-commit
Executable file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "running cargo check..."
|
||||||
|
|
||||||
|
./check-all.sh
|
||||||
|
STATUS=$?
|
||||||
|
|
||||||
|
if [ $STATUS -ne 0 ]; then
|
||||||
|
echo "cargo check failed, aborting"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "cargo check passed"
|
||||||
|
exit 0
|
||||||
13
check-all.sh
Executable file
13
check-all.sh
Executable file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
EDITIONS=$(yq ea "." editions.yaml | yq 'keys[]')
|
||||||
|
IFS=$'\n'
|
||||||
|
while IFS=$'\n' read -r EDITION; do
|
||||||
|
if [[ $(yq ea ".$EDITION.include-in-checkall" editions.yaml) == "true" ]]
|
||||||
|
then
|
||||||
|
export EDITION
|
||||||
|
./check-edition.sh $EDITION
|
||||||
|
fi
|
||||||
|
done <<< "$EDITIONS"
|
||||||
16
check-edition.sh
Executable file
16
check-edition.sh
Executable file
|
|
@ -0,0 +1,16 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [ -z ${EDITION+x} ]; then
|
||||||
|
export EDITION=$1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# comma seperated list of features for the specified version
|
||||||
|
source ./buildscripts/common.sh
|
||||||
|
echo CHECKING $EDITION
|
||||||
|
echo FEATURES:
|
||||||
|
echo $EDITION_FEATURES
|
||||||
|
|
||||||
|
cargo check --features "$EDITION_FEATURES"
|
||||||
|
|
@ -1,34 +1,100 @@
|
||||||
wiiu-chat:
|
wii-sports-club:
|
||||||
|
include-in-checkall: true
|
||||||
features:
|
features:
|
||||||
- prudpv1
|
- prudpv1
|
||||||
|
- third-notif-param
|
||||||
- v3-8-15
|
- v3-8-15
|
||||||
|
settings:
|
||||||
|
AUTH_REPORT_VERSION: "branch:origin/project/appsp build:3_4_24_4_0"
|
||||||
|
RNEX_VIRTUAL_PORT_INSECURE: "1:10"
|
||||||
|
RNEX_VIRTUAL_PORT_SECURE: "1:10"
|
||||||
|
RNEX_DEFAULT_PORT: 10000
|
||||||
|
RNEX_ACCESS_KEY: "4d324052"
|
||||||
|
puyopuyo:
|
||||||
|
include-in-checkall: true
|
||||||
|
features:
|
||||||
|
- prudpv1
|
||||||
|
- third-notif-param
|
||||||
|
- v3-8-15
|
||||||
|
settings:
|
||||||
|
AUTH_REPORT_VERSION: "branch:origin/release/ngs/3.5.x.1000 build:3_5_16_1000_0"
|
||||||
|
RNEX_VIRTUAL_PORT_INSECURE: "1:10"
|
||||||
|
RNEX_VIRTUAL_PORT_SECURE: "1:10"
|
||||||
|
RNEX_DEFAULT_PORT: 10000
|
||||||
|
RNEX_ACCESS_KEY: "4eb0ca36"
|
||||||
|
minecraft-wiiu:
|
||||||
|
include-in-checkall: true
|
||||||
|
features:
|
||||||
|
- prudpv1
|
||||||
|
- third-notif-param
|
||||||
|
- v3-10-22
|
||||||
|
settings:
|
||||||
|
AUTH_REPORT_VERSION: "branch:origin/release/ngs/3.10.x.200x build:3_10_22_2006_0"
|
||||||
|
RNEX_VIRTUAL_PORT_INSECURE: "1:10"
|
||||||
|
RNEX_VIRTUAL_PORT_SECURE: "1:10"
|
||||||
|
RNEX_DEFAULT_PORT: 13000
|
||||||
|
RNEX_ACCESS_KEY: "f1b61c8e"
|
||||||
|
mario-tennis:
|
||||||
|
include-in-checkall: true
|
||||||
|
features:
|
||||||
|
- prudpv1
|
||||||
|
- third-notif-param
|
||||||
|
- v3-8-15
|
||||||
|
settings:
|
||||||
|
AUTH_REPORT_VERSION: "branch:origin/release/ngs/3.9.x.200x build:3_9_19_2005_0"
|
||||||
|
RNEX_VIRTUAL_PORT_INSECURE: "1:10"
|
||||||
|
RNEX_VIRTUAL_PORT_SECURE: "1:10"
|
||||||
|
RNEX_DEFAULT_PORT: 10000
|
||||||
|
RNEX_ACCESS_KEY: "c69b92a0"
|
||||||
|
wii-u-chat:
|
||||||
|
include-in-checkall: true
|
||||||
|
features:
|
||||||
|
- prudpv1
|
||||||
|
- third-notif-param
|
||||||
|
- v3-3-2
|
||||||
settings:
|
settings:
|
||||||
AUTH_REPORT_VERSION: "branch:origin/project/wup-agmj build:3_8_15_2004_0"
|
AUTH_REPORT_VERSION: "branch:origin/project/wup-agmj build:3_8_15_2004_0"
|
||||||
RNEX_VIRTUAL_PORT_INSECURE: "1:10"
|
RNEX_VIRTUAL_PORT_INSECURE: "1:10"
|
||||||
RNEX_VIRTUAL_PORT_SECURE: "1:10"
|
RNEX_VIRTUAL_PORT_SECURE: "1:10"
|
||||||
RNEX_DEFAULT_PORT: 10000
|
RNEX_DEFAULT_PORT: 10000
|
||||||
RNEX_ACCESS_KEY: "e7a47214"
|
RNEX_ACCESS_KEY: "e7a47214"
|
||||||
splatoon:
|
fast-racing-neo:
|
||||||
|
include-in-checkall: true
|
||||||
features:
|
features:
|
||||||
- prudpv1
|
- prudpv1
|
||||||
- v3-8-15
|
- v3-8-15
|
||||||
|
settings:
|
||||||
|
AUTH_REPORT_VERSION: "branch:origin/release/ngs/3.9.x.200x build:3_9_19_2005_0"
|
||||||
|
RNEX_VIRTUAL_PORT_INSECURE: "1:10"
|
||||||
|
RNEX_VIRTUAL_PORT_SECURE: "1:10"
|
||||||
|
RNEX_DEFAULT_PORT: 10000
|
||||||
|
RNEX_ACCESS_KEY: "811aa39f"
|
||||||
|
splatoon:
|
||||||
|
include-in-checkall: true
|
||||||
|
features:
|
||||||
|
- prudpv1
|
||||||
|
- v3-8-15
|
||||||
|
- splatoon
|
||||||
settings:
|
settings:
|
||||||
AUTH_REPORT_VERSION: "branch:origin/project/wup-agmj build:3_8_15_2004_0"
|
AUTH_REPORT_VERSION: "branch:origin/project/wup-agmj build:3_8_15_2004_0"
|
||||||
RNEX_VIRTUAL_PORT_INSECURE: "1:10"
|
RNEX_VIRTUAL_PORT_INSECURE: "1:10"
|
||||||
RNEX_VIRTUAL_PORT_SECURE: "1:10"
|
RNEX_VIRTUAL_PORT_SECURE: "1:10"
|
||||||
RNEX_DEFAULT_PORT: 6000
|
RNEX_DEFAULT_PORT: 6000
|
||||||
RNEX_ACCESS_KEY: "6f599f81"
|
RNEX_ACCESS_KEY: "6f599f81"
|
||||||
splatoon2:
|
splatoon-testfire:
|
||||||
|
include-in-checkall: true
|
||||||
features:
|
features:
|
||||||
- v4-3-11
|
- prudpv1
|
||||||
- prudplite
|
- v3-8-15
|
||||||
- nx
|
- splatoon
|
||||||
settings:
|
settings:
|
||||||
AUTH_REPORT_VERSION: "branch:origin/project/wup-agmj build:3_8_15_2004_0"
|
AUTH_REPORT_VERSION: "branch:origin/project/wup-agmj build:3_8_15_2004_0"
|
||||||
RNEX_VIRTUAL_PORT_INSECURE: "1:10"
|
RNEX_VIRTUAL_PORT_INSECURE: "1:10"
|
||||||
RNEX_VIRTUAL_PORT_SECURE: "1:10"
|
RNEX_VIRTUAL_PORT_SECURE: "1:10"
|
||||||
RNEX_DEFAULT_PORT: 6000
|
RNEX_DEFAULT_PORT: 10000
|
||||||
|
RNEX_ACCESS_KEY: "da693ee5"
|
||||||
friends:
|
friends:
|
||||||
|
include-in-checkall: false
|
||||||
features:
|
features:
|
||||||
- friends
|
- friends
|
||||||
settings:
|
settings:
|
||||||
|
|
@ -38,6 +104,7 @@ friends:
|
||||||
RNEX_DEFAULT_PORT: 6000
|
RNEX_DEFAULT_PORT: 6000
|
||||||
RNEX_ACCESS_KEY: "ridfebb9"
|
RNEX_ACCESS_KEY: "ridfebb9"
|
||||||
super-mario-maker:
|
super-mario-maker:
|
||||||
|
include-in-checkall: false
|
||||||
features:
|
features:
|
||||||
- prudpv1
|
- prudpv1
|
||||||
- v3-8-15
|
- v3-8-15
|
||||||
|
|
|
||||||
|
|
@ -1,400 +1,27 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
mod protos;
|
mod protos;
|
||||||
|
mod rmc_struct;
|
||||||
|
mod util;
|
||||||
|
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
|
||||||
use crate::protos::{ProtoMethodData, RmcProtocolData};
|
use crate::protos::{ProtoInputParams, RmcProtocolData};
|
||||||
|
use crate::rmc_struct::{rmc_serialize_enum, rmc_serialize_struct};
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::{Ident, Literal, Span};
|
use proc_macro2::Ident;
|
||||||
use quote::{quote, TokenStreamExt};
|
use quote::quote;
|
||||||
use syn::parse::{Parse, ParseStream};
|
|
||||||
use syn::punctuated::Punctuated;
|
|
||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use syn::{
|
use syn::{parse_macro_input, Data, DeriveInput, Lit, LitStr};
|
||||||
parse_macro_input, Attribute, Data, DataStruct, DeriveInput, Fields, FnArg, Lit, LitInt,
|
|
||||||
LitStr, Pat, Token, TraitItem,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ProtoInputParams {
|
|
||||||
proto_num: LitInt,
|
|
||||||
properties: Option<(Token![,], Punctuated<Ident, Token![,]>)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for ProtoInputParams {
|
|
||||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
|
||||||
let proto_num = input.parse()?;
|
|
||||||
|
|
||||||
if let Some(seperator) = input.parse()? {
|
|
||||||
let mut punctuated = Punctuated::new();
|
|
||||||
loop {
|
|
||||||
punctuated.push_value(input.parse()?);
|
|
||||||
if let Some(punct) = input.parse()? {
|
|
||||||
punctuated.push_punct(punct);
|
|
||||||
} else {
|
|
||||||
return Ok(Self {
|
|
||||||
proto_num,
|
|
||||||
properties: Some((seperator, punctuated)),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(Self {
|
|
||||||
proto_num,
|
|
||||||
properties: None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_serialize_data_struct(
|
|
||||||
s: DataStruct,
|
|
||||||
struct_attr: Option<&Attribute>,
|
|
||||||
) -> (
|
|
||||||
proc_macro2::TokenStream,
|
|
||||||
proc_macro2::TokenStream,
|
|
||||||
proc_macro2::TokenStream,
|
|
||||||
) {
|
|
||||||
let serialize_base_content = {
|
|
||||||
let mut serialize_content = quote! {};
|
|
||||||
|
|
||||||
for f in &s.fields {
|
|
||||||
if f.attrs.iter().any(|a| {
|
|
||||||
a.path().segments.len() == 1
|
|
||||||
&& a.path()
|
|
||||||
.segments
|
|
||||||
.first()
|
|
||||||
.is_some_and(|p| p.ident.to_string() == "extends")
|
|
||||||
}) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let ident = f.ident.as_ref().unwrap();
|
|
||||||
|
|
||||||
serialize_content.append_all(quote! {
|
|
||||||
rnex_core::rmc::structures::RmcSerialize::serialize(&self.#ident, writer)?;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#serialize_content
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let struct_ctor = {
|
|
||||||
let mut structure_content = quote! {};
|
|
||||||
for f in &s.fields {
|
|
||||||
let ident = f.ident.as_ref().unwrap();
|
|
||||||
|
|
||||||
structure_content.append_all(quote! {#ident, });
|
|
||||||
}
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
Ok(Self{
|
|
||||||
#structure_content
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let deserialize_base_content = {
|
|
||||||
let mut deserialize_content = quote! {};
|
|
||||||
|
|
||||||
for f in &s.fields {
|
|
||||||
if f.attrs.iter().any(|a| {
|
|
||||||
a.path().segments.len() == 1
|
|
||||||
&& a.path()
|
|
||||||
.segments
|
|
||||||
.first()
|
|
||||||
.is_some_and(|p| p.ident.to_string() == "extends")
|
|
||||||
}) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let ident = f.ident.as_ref().unwrap();
|
|
||||||
let ty = &f.ty;
|
|
||||||
|
|
||||||
deserialize_content.append_all(quote! {
|
|
||||||
let #ident = <#ty> :: deserialize(reader)?;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#deserialize_content
|
|
||||||
#struct_ctor
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let write_size = {
|
|
||||||
let mut size_content = quote! { 0 };
|
|
||||||
|
|
||||||
for f in &s.fields {
|
|
||||||
let ident = f.ident.as_ref().unwrap();
|
|
||||||
|
|
||||||
size_content.append_all(quote! {
|
|
||||||
+ rnex_core::rmc::structures::RmcSerialize::serialize_write_size(&self.#ident)?
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
size_content
|
|
||||||
};
|
|
||||||
let write_size = if let Some(_) = struct_attr {
|
|
||||||
quote! { #write_size + if rnex_core::config::FEATURE_HAS_STRUCT_HEADER{ 5 } else { 0 } }
|
|
||||||
} else {
|
|
||||||
write_size
|
|
||||||
};
|
|
||||||
|
|
||||||
// generate base with extends stuff
|
|
||||||
|
|
||||||
let serialize_base_content = if let Some(attr) = struct_attr {
|
|
||||||
let version: Literal = attr.parse_args().expect("has to be a literal");
|
|
||||||
|
|
||||||
let pre_inner = if let Some(f) = s.fields.iter().find(|f| {
|
|
||||||
f.attrs.iter().any(|a| {
|
|
||||||
a.path().segments.len() == 1
|
|
||||||
&& a.path()
|
|
||||||
.segments
|
|
||||||
.first()
|
|
||||||
.is_some_and(|p| p.ident.to_string() == "extends")
|
|
||||||
})
|
|
||||||
}) {
|
|
||||||
let ident = f.ident.as_ref().unwrap();
|
|
||||||
quote! {
|
|
||||||
self.#ident.serialize(writer)?;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
quote! {}
|
|
||||||
};
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#pre_inner
|
|
||||||
rnex_core::rmc::structures::rmc_struct::write_struct(
|
|
||||||
writer,
|
|
||||||
#version,
|
|
||||||
rnex_core::rmc::structures::helpers::len_of_write(
|
|
||||||
|writer|{
|
|
||||||
#serialize_base_content
|
|
||||||
}
|
|
||||||
),
|
|
||||||
|writer|{
|
|
||||||
#serialize_base_content
|
|
||||||
}
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
serialize_base_content
|
|
||||||
};
|
|
||||||
|
|
||||||
let deserialize_base_content = if let Some(attr) = struct_attr {
|
|
||||||
let version: Literal = attr.parse_args().expect("has to be a literal");
|
|
||||||
|
|
||||||
let pre_inner = if let Some(f) = s.fields.iter().find(|f| {
|
|
||||||
f.attrs.iter().any(|a| {
|
|
||||||
a.path().segments.len() == 1
|
|
||||||
&& a.path()
|
|
||||||
.segments
|
|
||||||
.first()
|
|
||||||
.is_some_and(|p| p.ident.to_string() == "extends")
|
|
||||||
})
|
|
||||||
}) {
|
|
||||||
let ident = f.ident.as_ref().unwrap();
|
|
||||||
let ty = &f.ty;
|
|
||||||
quote! {
|
|
||||||
let #ident = <#ty> :: deserialize(reader)?;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
quote! {}
|
|
||||||
};
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#pre_inner
|
|
||||||
Ok(rnex_core::rmc::structures::rmc_struct::read_struct(reader, #version, move |mut reader|{
|
|
||||||
#deserialize_base_content
|
|
||||||
})?)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
deserialize_base_content
|
|
||||||
};
|
|
||||||
|
|
||||||
let write_size = quote! {
|
|
||||||
fn serialize_write_size(&self) -> rnex_core::rmc::structures::Result<u32>{
|
|
||||||
Ok(#write_size)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
(serialize_base_content, deserialize_base_content, write_size)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[proc_macro_derive(RmcSerialize, attributes(extends, rmc_struct))]
|
#[proc_macro_derive(RmcSerialize, attributes(extends, rmc_struct))]
|
||||||
pub fn rmc_serialize(input: TokenStream) -> TokenStream {
|
pub fn rmc_serialize(input: TokenStream) -> TokenStream {
|
||||||
let derive_input = parse_macro_input!(input as DeriveInput);
|
let derive_input = parse_macro_input!(input as DeriveInput);
|
||||||
|
|
||||||
let struct_attr = derive_input.attrs.iter().find(|a| {
|
let (serialize, deserialize, write_size, version) = match &derive_input.data {
|
||||||
a.path().segments.len() == 1
|
Data::Struct(s) => rmc_serialize_struct(s, &derive_input),
|
||||||
&& a.path()
|
Data::Enum(e) => rmc_serialize_enum(e, &derive_input),
|
||||||
.segments
|
|
||||||
.first()
|
|
||||||
.is_some_and(|p| p.ident.to_string() == "rmc_struct")
|
|
||||||
});
|
|
||||||
let repr_attr = derive_input.attrs.iter().find(|a| {
|
|
||||||
a.path().segments.len() == 1
|
|
||||||
&& a.path()
|
|
||||||
.segments
|
|
||||||
.first()
|
|
||||||
.is_some_and(|p| p.ident.to_string() == "repr")
|
|
||||||
});
|
|
||||||
|
|
||||||
/*let Data::Struct(s) = derive_input.data else {
|
|
||||||
panic!("rmc struct type MUST be a struct");
|
|
||||||
};*/
|
|
||||||
|
|
||||||
let (serialize_base_content, deserialize_base_content, write_size) = match derive_input.data {
|
|
||||||
Data::Struct(s) => gen_serialize_data_struct(s, struct_attr),
|
|
||||||
Data::Enum(e) => {
|
|
||||||
let Some(repr_attr) = repr_attr else {
|
|
||||||
panic!("missing repr attribute");
|
|
||||||
};
|
|
||||||
|
|
||||||
let ty: Ident = repr_attr.parse_args().unwrap();
|
|
||||||
|
|
||||||
let mut inner_match_de = quote! {};
|
|
||||||
let mut inner_match_se = quote! {};
|
|
||||||
//let mut inner_match_len = quote!{};
|
|
||||||
|
|
||||||
for variant in e.variants {
|
|
||||||
let Some((_, val)) = variant.discriminant else {
|
|
||||||
panic!("missing discriminant");
|
|
||||||
};
|
|
||||||
|
|
||||||
let field_data_de = match &variant.fields {
|
|
||||||
Fields::Named(v) => {
|
|
||||||
let mut base = quote! {};
|
|
||||||
for field in v.named.iter() {
|
|
||||||
let ty = &field.ty;
|
|
||||||
let name = &field.ident;
|
|
||||||
|
|
||||||
base.append_all(quote!{
|
|
||||||
#name: <#ty as rnex_core::rmc::structures::RmcSerialize>::deserialize(reader)?,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
quote! {{#base}}
|
|
||||||
}
|
|
||||||
Fields::Unnamed(n) => {
|
|
||||||
let mut base = quote! {};
|
|
||||||
|
|
||||||
for field in n.unnamed.iter() {
|
|
||||||
let ty = &field.ty;
|
|
||||||
|
|
||||||
base.append_all(quote!{
|
|
||||||
<#ty as rnex_core::rmc::structures::RmcSerialize>::deserialize(reader)?,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
quote! {(#base)}
|
|
||||||
}
|
|
||||||
Fields::Unit => {
|
|
||||||
quote! {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut se_with_fields = quote! {
|
|
||||||
<#ty as rnex_core::rmc::structures::RmcSerialize>::serialize(&#val, writer)?;
|
|
||||||
};
|
|
||||||
|
|
||||||
match &variant.fields {
|
|
||||||
Fields::Named(v) => {
|
|
||||||
for field in v.named.iter() {
|
|
||||||
let ty = &field.ty;
|
|
||||||
let name = &field.ident;
|
|
||||||
|
|
||||||
se_with_fields.append_all(quote!{
|
|
||||||
<#ty as rnex_core::rmc::structures::RmcSerialize>::serialize(#name ,writer)?;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Fields::Unnamed(n) => {
|
|
||||||
for (i, field) in n.unnamed.iter().enumerate() {
|
|
||||||
let ty = &field.ty;
|
|
||||||
|
|
||||||
let ident = Ident::new(&format!("val_{}", i), Span::call_site());
|
|
||||||
|
|
||||||
se_with_fields.append_all(quote!{
|
|
||||||
<#ty as rnex_core::rmc::structures::RmcSerialize>::serialize(#ident, writer)?;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Fields::Unit => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
let field_match_se = match &variant.fields {
|
|
||||||
Fields::Named(v) => {
|
|
||||||
let mut base = quote! {};
|
|
||||||
|
|
||||||
for field in v.named.iter() {
|
|
||||||
let name = &field.ident;
|
|
||||||
|
|
||||||
base.append_all(quote! {
|
|
||||||
#name,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
quote! {{#base}}
|
|
||||||
}
|
|
||||||
Fields::Unnamed(n) => {
|
|
||||||
let mut base = quote! {};
|
|
||||||
|
|
||||||
for (i, _field) in n.unnamed.iter().enumerate() {
|
|
||||||
let ident = Ident::new(&format!("val_{}", i), Span::call_site());
|
|
||||||
|
|
||||||
base.append_all(quote! {
|
|
||||||
#ident,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
quote! {(#base)}
|
|
||||||
}
|
|
||||||
Fields::Unit => {
|
|
||||||
quote! {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let name = variant.ident;
|
|
||||||
|
|
||||||
inner_match_de.append_all(quote! {
|
|
||||||
#val => Self::#name #field_data_de,
|
|
||||||
});
|
|
||||||
|
|
||||||
inner_match_se.append_all(quote! {
|
|
||||||
Self::#name #field_match_se => {
|
|
||||||
#se_with_fields
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let serialize_base_content = quote! {
|
|
||||||
match self{
|
|
||||||
#inner_match_se
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
};
|
|
||||||
|
|
||||||
let deserialize_base_content = quote! {
|
|
||||||
let val: Self = match <#ty as rnex_core::rmc::structures::RmcSerialize>::deserialize(reader)?{
|
|
||||||
#inner_match_de
|
|
||||||
v => return Err(rnex_core::rmc::structures::Error::UnexpectedValue(v as _))
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(val)
|
|
||||||
};
|
|
||||||
|
|
||||||
(serialize_base_content, deserialize_base_content, quote! {})
|
|
||||||
}
|
|
||||||
Data::Union(_) => {
|
Data::Union(_) => {
|
||||||
unimplemented!()
|
unimplemented!("serialize a union is not allowed");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -406,19 +33,41 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream {
|
||||||
));
|
));
|
||||||
let ident = derive_input.ident;
|
let ident = derive_input.ident;
|
||||||
|
|
||||||
|
let write_size = if let Some(v) = write_size {
|
||||||
|
quote! {
|
||||||
|
fn serialize_write_size(&self) -> rnex_core::rmc::structures::Result<u32>{
|
||||||
|
#v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {}
|
||||||
|
};
|
||||||
|
|
||||||
|
let version = if let Some(v) = version {
|
||||||
|
quote! {
|
||||||
|
fn version() -> Option<u8>{
|
||||||
|
#v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {}
|
||||||
|
};
|
||||||
|
|
||||||
let tokens = quote! {
|
let tokens = quote! {
|
||||||
impl rnex_core::rmc::structures::RmcSerialize for #ident{
|
impl rnex_core::rmc::structures::RmcSerialize for #ident{
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn serialize(&self, writer: &mut impl ::std::io::Write) -> rnex_core::rmc::structures::Result<()>{
|
fn serialize(&self, writer: &mut impl ::std::io::Write) -> rnex_core::rmc::structures::Result<()>{
|
||||||
#serialize_base_content
|
#serialize
|
||||||
}
|
}
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn deserialize(reader: &mut impl ::std::io::Read) -> rnex_core::rmc::structures::Result<Self>{
|
fn deserialize(reader: &mut impl ::std::io::Read) -> rnex_core::rmc::structures::Result<Self>{
|
||||||
#deserialize_base_content
|
#deserialize
|
||||||
}
|
}
|
||||||
|
|
||||||
#write_size
|
#write_size
|
||||||
|
|
||||||
|
#version
|
||||||
|
|
||||||
fn name() -> &'static str{
|
fn name() -> &'static str{
|
||||||
#str_name
|
#str_name
|
||||||
}
|
}
|
||||||
|
|
@ -455,71 +104,9 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream {
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn rmc_proto(attr: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn rmc_proto(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
let params = parse_macro_input!(attr as ProtoInputParams);
|
let params = parse_macro_input!(attr as ProtoInputParams);
|
||||||
|
|
||||||
let ProtoInputParams {
|
|
||||||
proto_num,
|
|
||||||
properties,
|
|
||||||
} = params;
|
|
||||||
|
|
||||||
let no_return_data =
|
|
||||||
properties.is_some_and(|p| p.1.iter().any(|i| i.to_string() == "NoReturn"));
|
|
||||||
|
|
||||||
let input = parse_macro_input!(input as syn::ItemTrait);
|
let input = parse_macro_input!(input as syn::ItemTrait);
|
||||||
|
|
||||||
// gigantic ass struct initializer (to summarize this gets all of the data)
|
let raw_data = RmcProtocolData::new(params, &input);
|
||||||
let raw_data = RmcProtocolData {
|
|
||||||
has_returns: !no_return_data,
|
|
||||||
name: input.ident.clone(),
|
|
||||||
id: proto_num,
|
|
||||||
methods: input
|
|
||||||
.items
|
|
||||||
.iter()
|
|
||||||
.filter_map(|v| match v {
|
|
||||||
TraitItem::Fn(v) => Some(v),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.map(|func| {
|
|
||||||
let Some(attr) = func.attrs.iter().find(|a| {
|
|
||||||
a.path()
|
|
||||||
.segments
|
|
||||||
.last()
|
|
||||||
.is_some_and(|s| s.ident.to_string() == "method_id")
|
|
||||||
}) else {
|
|
||||||
panic!("every function inside of an rmc protocol must have a method id");
|
|
||||||
};
|
|
||||||
|
|
||||||
let Ok(id): Result<LitInt, _> = attr.parse_args() else {
|
|
||||||
panic!("todo: put a propper error message here");
|
|
||||||
};
|
|
||||||
|
|
||||||
let funcs = func
|
|
||||||
.sig
|
|
||||||
.inputs
|
|
||||||
.iter()
|
|
||||||
.skip(1)
|
|
||||||
.map(|f| {
|
|
||||||
let FnArg::Typed(t) = f else {
|
|
||||||
panic!("what");
|
|
||||||
};
|
|
||||||
let Pat::Ident(i) = &*t.pat else {
|
|
||||||
panic!(
|
|
||||||
"unable to handle non identifier patterns as parameter bindings"
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
(i.ident.clone(), t.ty.as_ref().clone())
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
ProtoMethodData {
|
|
||||||
id,
|
|
||||||
name: func.sig.ident.clone(),
|
|
||||||
parameters: funcs,
|
|
||||||
ret_val: func.sig.output.clone(),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
};
|
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#input
|
#input
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,48 @@
|
||||||
use proc_macro2::{Ident, Span, TokenStream};
|
use proc_macro2::{Ident, Span, TokenStream};
|
||||||
use quote::{quote, ToTokens};
|
use quote::{quote, ToTokens};
|
||||||
use syn::token::{Brace, Paren, Semi};
|
use syn::{
|
||||||
use syn::{Attribute, LitInt, LitStr, ReturnType, Type};
|
parse::{Parse, ParseStream},
|
||||||
|
punctuated::Punctuated,
|
||||||
|
Attribute, FnArg, ItemTrait, LitInt, LitStr, Meta, Pat, ReturnType, Token, TraitItem, Type,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::util::fold_tokenable;
|
||||||
|
|
||||||
|
pub struct ProtoInputParams {
|
||||||
|
proto_num: LitInt,
|
||||||
|
properties: Option<(Token![,], Punctuated<Ident, Token![,]>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for ProtoInputParams {
|
||||||
|
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||||
|
let proto_num = input.parse()?;
|
||||||
|
|
||||||
|
if let Some(seperator) = input.parse()? {
|
||||||
|
let mut punctuated = Punctuated::new();
|
||||||
|
loop {
|
||||||
|
punctuated.push_value(input.parse()?);
|
||||||
|
if let Some(punct) = input.parse()? {
|
||||||
|
punctuated.push_punct(punct);
|
||||||
|
} else {
|
||||||
|
return Ok(Self {
|
||||||
|
proto_num,
|
||||||
|
properties: Some((seperator, punctuated)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(Self {
|
||||||
|
proto_num,
|
||||||
|
properties: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
pub struct ProtoMethodData {
|
pub struct ProtoMethodData {
|
||||||
pub id: LitInt,
|
pub id: LitInt,
|
||||||
pub name: Ident,
|
pub name: Ident,
|
||||||
pub parameters: Vec<(Ident, Type)>,
|
pub attributes: Vec<Attribute>,
|
||||||
|
pub parameters: Vec<(Ident, Type, Vec<Attribute>)>,
|
||||||
pub ret_val: ReturnType,
|
pub ret_val: ReturnType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -23,108 +59,222 @@ pub struct RmcProtocolData {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RmcProtocolData {
|
impl RmcProtocolData {
|
||||||
fn generate_raw_trait(&self, tokens: &mut TokenStream) {
|
pub fn new(params: ProtoInputParams, input: &ItemTrait) -> Self {
|
||||||
|
let ProtoInputParams {
|
||||||
|
proto_num,
|
||||||
|
properties,
|
||||||
|
} = params;
|
||||||
|
|
||||||
|
let no_return_data =
|
||||||
|
properties.is_some_and(|p| p.1.iter().any(|i| i.to_string() == "NoReturn"));
|
||||||
|
|
||||||
|
// gigantic ass struct initializer (to summarize this gets all of the data)
|
||||||
|
RmcProtocolData {
|
||||||
|
has_returns: !no_return_data,
|
||||||
|
name: input.ident.clone(),
|
||||||
|
id: proto_num,
|
||||||
|
methods: input
|
||||||
|
.items
|
||||||
|
.iter()
|
||||||
|
.filter_map(|v| match v {
|
||||||
|
TraitItem::Fn(v) => Some(v),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|func| {
|
||||||
|
let Some(attr) = func.attrs.iter().find(|a| {
|
||||||
|
a.path()
|
||||||
|
.segments
|
||||||
|
.last()
|
||||||
|
.is_some_and(|s| s.ident.to_string() == "method_id")
|
||||||
|
}) else {
|
||||||
|
panic!("every function inside of an rmc protocol must have a method id");
|
||||||
|
};
|
||||||
|
|
||||||
|
let Ok(id): Result<LitInt, _> = attr.parse_args() else {
|
||||||
|
panic!("todo: put a propper error message here");
|
||||||
|
};
|
||||||
|
|
||||||
|
let funcs = func
|
||||||
|
.sig
|
||||||
|
.inputs
|
||||||
|
.iter()
|
||||||
|
.skip(1)
|
||||||
|
.map(|f| {
|
||||||
|
let FnArg::Typed(t) = f else {
|
||||||
|
panic!("what");
|
||||||
|
};
|
||||||
|
let Pat::Ident(i) = &*t.pat else {
|
||||||
|
panic!(
|
||||||
|
"unable to handle non identifier patterns as parameter bindings"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
(i.ident.clone(), t.ty.as_ref().clone(), t.attrs.clone())
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
ProtoMethodData {
|
||||||
|
id,
|
||||||
|
name: func.sig.ident.clone(),
|
||||||
|
parameters: funcs,
|
||||||
|
ret_val: func.sig.output.clone(),
|
||||||
|
attributes: func
|
||||||
|
.attrs
|
||||||
|
.iter()
|
||||||
|
.filter(|a| match &a.meta {
|
||||||
|
Meta::NameValue(v) => {
|
||||||
|
if let Some(i) = v.path.get_ident() {
|
||||||
|
i.to_string() != "doc"
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Meta::List(l) => {
|
||||||
|
if let Some(seg) = l.path.segments.last() {
|
||||||
|
seg.ident.to_string() != "method_id"
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => true,
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_raw_trait(&self) -> TokenStream {
|
||||||
let Self {
|
let Self {
|
||||||
has_returns,
|
has_returns,
|
||||||
name,
|
name,
|
||||||
id,
|
id,
|
||||||
methods,
|
methods,
|
||||||
} = self;
|
} = self;
|
||||||
|
let generate_raw_method = |method: &ProtoMethodData| -> TokenStream {
|
||||||
|
let ProtoMethodData {
|
||||||
|
name,
|
||||||
|
parameters,
|
||||||
|
attributes,
|
||||||
|
..
|
||||||
|
} = method;
|
||||||
|
|
||||||
// this gives us the name which the identifier of the corresponding Raw trait
|
let attribs = fold_tokenable(attributes.iter());
|
||||||
let raw_name = Ident::new(&format!("Raw{}", name), name.span());
|
|
||||||
|
|
||||||
// boilerplate tokens which all raw traits need
|
let raw_name = Ident::new(&format!("raw_{}", name), name.span());
|
||||||
quote! {
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[allow(unused_must_use)]
|
|
||||||
pub trait #raw_name: #name
|
|
||||||
}
|
|
||||||
.to_tokens(tokens);
|
|
||||||
|
|
||||||
// generate the body of the raw protocol trait
|
let optional_return = if self.has_returns {
|
||||||
Brace::default().surround(tokens, |tokens|{
|
quote! {
|
||||||
//generate each raw method
|
-> ::core::result::Result<Vec<u8>, ::rnex_core::rmc::response::ErrorCode>
|
||||||
for method in methods{
|
}
|
||||||
let ProtoMethodData {
|
} else {
|
||||||
name,
|
quote! {}
|
||||||
parameters,
|
}
|
||||||
..
|
.into_token_stream();
|
||||||
} = method;
|
|
||||||
|
|
||||||
let raw_name = Ident::new(&format!("raw_{}", name), name.span());
|
let deser_params =
|
||||||
quote!{
|
fold_tokenable(parameters.iter().map(|(param_name, param_type, attribs)| {
|
||||||
#[inline(always)]
|
let error_msg = LitStr::new(
|
||||||
async fn #raw_name
|
&format!("an error occurred whilest deserializing {}", param_name),
|
||||||
}.to_tokens(tokens);
|
Span::call_site(),
|
||||||
|
);
|
||||||
Paren::default().surround(tokens, |tokens|{
|
let return_from_deser_error = if self.has_returns {
|
||||||
quote!{ &self, data: ::std::vec::Vec<u8> }.to_tokens(tokens);
|
quote! {
|
||||||
});
|
return Err(::rnex_core::rmc::response::ErrorCode::Core_InvalidArgument);
|
||||||
|
}
|
||||||
if self.has_returns {
|
} else {
|
||||||
|
quote! {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let attribs = fold_tokenable(attribs.iter());
|
||||||
quote! {
|
quote! {
|
||||||
-> ::core::result::Result<Vec<u8>, ErrorCode>
|
#attribs
|
||||||
}.to_tokens(tokens);
|
let Ok(#param_name) =
|
||||||
|
<#param_type as rnex_core::rmc::structures::RmcSerialize>::deserialize(
|
||||||
|
&mut cursor
|
||||||
|
) else{
|
||||||
|
log::error!(#error_msg);
|
||||||
|
#return_from_deser_error
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
let call_params = fold_tokenable(parameters.iter().map(|(param_name, _, attribs)| {
|
||||||
|
let attribs = fold_tokenable(attribs.iter());
|
||||||
|
quote! {
|
||||||
|
#attribs
|
||||||
|
#param_name,
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
let optional_method_return = if *has_returns {
|
||||||
|
quote! {
|
||||||
|
let retval = retval?;
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
rnex_core::rmc::structures::RmcSerialize::serialize(&retval, &mut vec).ok();
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {}
|
||||||
|
};
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#[inline(always)]
|
||||||
|
#attribs
|
||||||
|
async fn #raw_name (&self, data: ::std::vec::Vec<u8>) #optional_return{
|
||||||
|
let mut cursor = ::std::io::Cursor::new(data);
|
||||||
|
#deser_params
|
||||||
|
let retval = self.#name(#call_params).await;
|
||||||
|
#optional_method_return
|
||||||
}
|
}
|
||||||
|
|
||||||
Brace::default().surround(tokens, |tokens|{
|
|
||||||
quote! { let mut cursor = ::std::io::Cursor::new(data); }.to_tokens(tokens);
|
|
||||||
|
|
||||||
for (param_name, param_type) in parameters{
|
|
||||||
quote!{
|
|
||||||
let Ok(#param_name) =
|
|
||||||
<#param_type as rnex_core::rmc::structures::RmcSerialize>::deserialize(
|
|
||||||
&mut cursor
|
|
||||||
) else
|
|
||||||
}.to_tokens(tokens);
|
|
||||||
|
|
||||||
let error_msg = LitStr::new(&format!("an error occurred whilest deserializing {}", param_name), Span::call_site());
|
|
||||||
|
|
||||||
if self.has_returns {
|
|
||||||
quote! {
|
|
||||||
{
|
|
||||||
log::error!(#error_msg);
|
|
||||||
return Err(rnex_core::rmc::response::ErrorCode::Core_InvalidArgument);
|
|
||||||
};
|
|
||||||
}.to_tokens(tokens)
|
|
||||||
} else {
|
|
||||||
quote! {
|
|
||||||
{
|
|
||||||
log::error!(#error_msg);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
}.to_tokens(tokens)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
quote!{
|
|
||||||
let retval = self.#name
|
|
||||||
}.to_tokens(tokens);
|
|
||||||
|
|
||||||
Paren::default().surround(tokens, |tokens|{
|
|
||||||
for (paren_name, _) in parameters{
|
|
||||||
quote!{#paren_name,}.to_tokens(tokens);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
quote!{
|
|
||||||
.await;
|
|
||||||
}.to_tokens(tokens);
|
|
||||||
|
|
||||||
if *has_returns{
|
|
||||||
quote!{
|
|
||||||
let retval = retval?;
|
|
||||||
let mut vec = Vec::new();
|
|
||||||
rnex_core::rmc::structures::RmcSerialize::serialize(&retval, &mut vec).ok();
|
|
||||||
Ok(vec)
|
|
||||||
}.to_tokens(tokens);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
quote!{
|
let generate_rmc_call_proto = || {
|
||||||
|
let method_entries = fold_tokenable(methods.iter().map(|m| {
|
||||||
|
let ProtoMethodData {
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
attributes,
|
||||||
|
..
|
||||||
|
} = m;
|
||||||
|
|
||||||
|
let attribs = fold_tokenable(attributes.iter());
|
||||||
|
let raw_name = Ident::new(&format!("raw_{}", name), name.span());
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#attribs
|
||||||
|
#id => self.#raw_name(data).await,
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
let optional_notimpl_return = if self.has_returns {
|
||||||
|
quote! {
|
||||||
|
Err(rnex_core::rmc::response::ErrorCode::Core_NotImplemented)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {}
|
||||||
|
};
|
||||||
|
|
||||||
|
let optional_result_sendback = if *has_returns {
|
||||||
|
quote! {
|
||||||
|
rnex_core::rmc::response::send_result(
|
||||||
|
remote_response_connection,
|
||||||
|
ret,
|
||||||
|
#id,
|
||||||
|
method_id,
|
||||||
|
call_id,
|
||||||
|
).await
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {}
|
||||||
|
};
|
||||||
|
|
||||||
|
quote! {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
async fn rmc_call_proto(
|
async fn rmc_call_proto(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -132,71 +282,38 @@ impl RmcProtocolData {
|
||||||
method_id: u32,
|
method_id: u32,
|
||||||
call_id: u32,
|
call_id: u32,
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
)
|
){
|
||||||
}.to_tokens(tokens);
|
let ret = match method_id{
|
||||||
|
#method_entries
|
||||||
Brace::default().surround(tokens, |tokens|{
|
v => {
|
||||||
quote! {
|
|
||||||
let ret = match method_id
|
|
||||||
}.to_tokens(tokens);
|
|
||||||
|
|
||||||
Brace::default().surround(tokens, |tokens|{
|
|
||||||
for method in methods{
|
|
||||||
let ProtoMethodData{
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
..
|
|
||||||
} = method;
|
|
||||||
|
|
||||||
let raw_name = Ident::new(&format!("raw_{}", name), name.span());
|
|
||||||
|
|
||||||
|
|
||||||
quote!{
|
|
||||||
#id => self.#raw_name(data).await,
|
|
||||||
}.to_tokens(tokens);
|
|
||||||
}
|
|
||||||
quote!{
|
|
||||||
v =>
|
|
||||||
}.to_tokens(tokens);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Brace::default().surround(tokens, |tokens|{
|
|
||||||
quote!{
|
|
||||||
log::error!("(protocol {})unimplemented method id called on protocol: {}", #id, v);
|
log::error!("(protocol {})unimplemented method id called on protocol: {}", #id, v);
|
||||||
}.to_tokens(tokens);
|
#optional_notimpl_return
|
||||||
if self.has_returns {
|
|
||||||
quote! {
|
|
||||||
Err(rnex_core::rmc::response::ErrorCode::Core_NotImplemented)
|
|
||||||
}.to_tokens(tokens);
|
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
#optional_result_sendback
|
||||||
});
|
|
||||||
|
|
||||||
Semi::default().to_tokens(tokens);
|
|
||||||
|
|
||||||
if *has_returns{
|
|
||||||
quote!{
|
|
||||||
rnex_core::rmc::response::send_result(
|
|
||||||
remote_response_connection,
|
|
||||||
ret,
|
|
||||||
#id,
|
|
||||||
method_id,
|
|
||||||
call_id,
|
|
||||||
).await
|
|
||||||
}.to_tokens(tokens);
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
// this gives us the name which the identifier of the corresponding Raw trait
|
||||||
|
let raw_name = Ident::new(&format!("Raw{}", name), name.span());
|
||||||
|
let proto_raw_methods = fold_tokenable(self.methods.iter().map(|m| generate_raw_method(m)));
|
||||||
|
let rmc_call_proto = generate_rmc_call_proto();
|
||||||
|
|
||||||
|
// boilerplate tokens which all raw traits need
|
||||||
quote! {
|
quote! {
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[allow(unused_must_use)]
|
||||||
|
pub trait #raw_name: #name{
|
||||||
|
#proto_raw_methods
|
||||||
|
#rmc_call_proto
|
||||||
|
}
|
||||||
impl<T: #name> #raw_name for T{}
|
impl<T: #name> #raw_name for T{}
|
||||||
}
|
}
|
||||||
.to_tokens(tokens);
|
.to_token_stream()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_raw_remote_trait(&self, tokens: &mut TokenStream) {
|
fn generate_raw_remote_trait(&self) -> TokenStream {
|
||||||
let Self {
|
let Self {
|
||||||
has_returns,
|
has_returns,
|
||||||
name,
|
name,
|
||||||
|
|
@ -207,101 +324,92 @@ impl RmcProtocolData {
|
||||||
|
|
||||||
// this gives us the name which the identifier of the corresponding Raw trait
|
// this gives us the name which the identifier of the corresponding Raw trait
|
||||||
let remote_name = Ident::new(&format!("Remote{}", name), name.span());
|
let remote_name = Ident::new(&format!("Remote{}", name), name.span());
|
||||||
|
let generate_remote_method = |m: &ProtoMethodData| -> TokenStream {
|
||||||
|
let ProtoMethodData {
|
||||||
|
name,
|
||||||
|
parameters,
|
||||||
|
ret_val,
|
||||||
|
attributes,
|
||||||
|
id: method_id,
|
||||||
|
} = m;
|
||||||
|
|
||||||
|
let params = fold_tokenable(parameters.iter().map(|(ident, ty, attr)| {
|
||||||
|
let attrs = fold_tokenable(attr.iter());
|
||||||
|
quote! { #attrs #ident: #ty, }
|
||||||
|
}));
|
||||||
|
|
||||||
|
let optional_questionmark_operator = if self.has_returns {
|
||||||
|
quote! {
|
||||||
|
?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {}
|
||||||
|
};
|
||||||
|
|
||||||
|
let param_serialize = fold_tokenable(parameters.iter().map(|(name, ty, attrs)|{
|
||||||
|
let attrs = fold_tokenable(attrs.iter());
|
||||||
|
quote!{
|
||||||
|
#attrs
|
||||||
|
rnex_core::result::ResultExtension::display_err_or_some(
|
||||||
|
<#ty as rnex_core::rmc::structures::RmcSerialize>::serialize(
|
||||||
|
&#name,
|
||||||
|
&mut cursor
|
||||||
|
)
|
||||||
|
).ok_or(rnex_core::rmc::response::ErrorCode::Core_InvalidArgument)#optional_questionmark_operator ;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
let make_call = if *has_returns {
|
||||||
|
quote! {
|
||||||
|
rnex_core::result::ResultExtension::display_err_or_some(
|
||||||
|
rmc_conn.make_raw_call(&message).await
|
||||||
|
).ok_or(rnex_core::rmc::response::ErrorCode::Core_Exception)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
rnex_core::result::ResultExtension::display_err_or_some(
|
||||||
|
rmc_conn.make_raw_call_no_response(&message).await
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let attribs = fold_tokenable(attributes.iter());
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#attribs
|
||||||
|
async fn #name(&self, #params) #ret_val{
|
||||||
|
let mut send_data = ::std::vec::Vec::new();
|
||||||
|
let mut cursor = ::std::io::Cursor::new(&mut send_data);
|
||||||
|
#param_serialize
|
||||||
|
|
||||||
|
let call_id = rand::random();
|
||||||
|
|
||||||
|
let message = rnex_core::rmc::message::RMCMessage{
|
||||||
|
call_id,
|
||||||
|
method_id: #method_id,
|
||||||
|
protocol_id: #proto_id,
|
||||||
|
rest_of_data: send_data
|
||||||
|
};
|
||||||
|
|
||||||
|
let rmc_conn = <Self as rnex_core::rmc::protocols::HasRmcConnection>::get_connection(self);
|
||||||
|
|
||||||
|
#make_call
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let remote_methods = fold_tokenable(methods.iter().map(|m| generate_remote_method(m)));
|
||||||
|
|
||||||
// boilerplate tokens which all raw traits need
|
|
||||||
quote! {
|
quote! {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(unused_must_use)]
|
#[allow(unused_must_use)]
|
||||||
pub trait #remote_name: rnex_core::rmc::protocols::HasRmcConnection
|
pub trait #remote_name: rnex_core::rmc::protocols::HasRmcConnection{
|
||||||
}
|
#remote_methods
|
||||||
.to_tokens(tokens);
|
|
||||||
|
|
||||||
// generate the body of the raw protocol trait
|
|
||||||
Brace::default().surround(tokens, |tokens|{
|
|
||||||
//generate each raw method
|
|
||||||
for method in methods{
|
|
||||||
let ProtoMethodData {
|
|
||||||
name,
|
|
||||||
parameters,
|
|
||||||
ret_val,
|
|
||||||
id: method_id,
|
|
||||||
..
|
|
||||||
} = method;
|
|
||||||
|
|
||||||
quote!{
|
|
||||||
async fn #name
|
|
||||||
}.to_tokens(tokens);
|
|
||||||
|
|
||||||
Paren::default().surround(tokens, |tokens|{
|
|
||||||
quote!{ &self, }.to_tokens(tokens);
|
|
||||||
for (param_ident, param_type) in parameters{
|
|
||||||
quote!{ #param_ident: #param_type, }.to_tokens(tokens);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
quote!{
|
|
||||||
#ret_val
|
|
||||||
}.to_tokens(tokens);
|
|
||||||
|
|
||||||
Brace::default().surround(tokens, |tokens|{
|
|
||||||
quote! {
|
|
||||||
let mut send_data = Vec::new();
|
|
||||||
let mut cursor = ::std::io::Cursor::new(&mut send_data);
|
|
||||||
}.to_tokens(tokens);
|
|
||||||
|
|
||||||
for (param_name, param_type) in parameters{
|
|
||||||
quote!{
|
|
||||||
rnex_core::result::ResultExtension::display_err_or_some(
|
|
||||||
<#param_type as rnex_core::rmc::structures::RmcSerialize>::serialize(
|
|
||||||
&#param_name,
|
|
||||||
&mut cursor
|
|
||||||
)
|
|
||||||
).ok_or(rnex_core::rmc::response::ErrorCode::Core_InvalidArgument)
|
|
||||||
}.to_tokens(tokens);
|
|
||||||
if self.has_returns {
|
|
||||||
quote! {
|
|
||||||
?;
|
|
||||||
}.to_tokens(tokens)
|
|
||||||
} else {
|
|
||||||
quote! {
|
|
||||||
;
|
|
||||||
}.to_tokens(tokens)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
quote!{
|
|
||||||
let call_id = rand::random();
|
|
||||||
|
|
||||||
let message = rnex_core::rmc::message::RMCMessage{
|
|
||||||
call_id,
|
|
||||||
method_id: #method_id,
|
|
||||||
protocol_id: #proto_id,
|
|
||||||
rest_of_data: send_data
|
|
||||||
};
|
|
||||||
|
|
||||||
let rmc_conn = <Self as rnex_core::rmc::protocols::HasRmcConnection>::get_connection(self);
|
|
||||||
}.to_tokens(tokens);
|
|
||||||
|
|
||||||
if *has_returns{
|
|
||||||
quote!{
|
|
||||||
rnex_core::result::ResultExtension::display_err_or_some(
|
|
||||||
rmc_conn.make_raw_call(&message).await
|
|
||||||
).ok_or(rnex_core::rmc::response::ErrorCode::Core_Exception)
|
|
||||||
}.to_tokens(tokens);
|
|
||||||
} else {
|
|
||||||
quote!{
|
|
||||||
rnex_core::result::ResultExtension::display_err_or_some(
|
|
||||||
rmc_conn.make_raw_call_no_response(&message).await
|
|
||||||
);
|
|
||||||
}.to_tokens(tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_raw_info(&self, tokens: &mut TokenStream) {
|
fn generate_raw_info(&self) -> TokenStream {
|
||||||
let Self { name, id, .. } = self;
|
let Self { name, id, .. } = self;
|
||||||
|
|
||||||
let raw_info_name = Ident::new(&format!("Raw{}Info", name), Span::call_site());
|
let raw_info_name = Ident::new(&format!("Raw{}Info", name), Span::call_site());
|
||||||
|
|
@ -314,14 +422,13 @@ impl RmcProtocolData {
|
||||||
pub const PROTOCOL_ID: u16 = #id;
|
pub const PROTOCOL_ID: u16 = #id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.to_tokens(tokens);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToTokens for RmcProtocolData {
|
impl ToTokens for RmcProtocolData {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
self.generate_raw_trait(tokens);
|
self.generate_raw_trait().to_tokens(tokens);
|
||||||
self.generate_raw_info(tokens);
|
self.generate_raw_info().to_tokens(tokens);
|
||||||
self.generate_raw_remote_trait(tokens);
|
self.generate_raw_remote_trait().to_tokens(tokens);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
426
macros/src/rmc_struct.rs
Normal file
426
macros/src/rmc_struct.rs
Normal file
|
|
@ -0,0 +1,426 @@
|
||||||
|
use proc_macro2::{Literal, Span, TokenStream};
|
||||||
|
use quote::quote;
|
||||||
|
use syn::{
|
||||||
|
bracketed, parse::Parse, punctuated::Punctuated, token::Bracket, DataEnum, DataStruct,
|
||||||
|
DeriveInput, Field, Fields, Ident, Meta, Token, Variant,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::util::fold_tokenable;
|
||||||
|
|
||||||
|
struct RmcStructAttrVersion {
|
||||||
|
bracket: Bracket,
|
||||||
|
delim: Token![,],
|
||||||
|
feature_name: Literal,
|
||||||
|
struct_version: Literal,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RmcStructAttr {
|
||||||
|
base_ver: Literal,
|
||||||
|
versions: Option<(Token![,], Punctuated<RmcStructAttrVersion, Token![,]>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for RmcStructAttr {
|
||||||
|
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||||
|
let base_ver = input.parse()?;
|
||||||
|
|
||||||
|
if let Some(seperator) = input.parse()? {
|
||||||
|
let mut punctuated = Punctuated::new();
|
||||||
|
loop {
|
||||||
|
punctuated.push_value(input.parse()?);
|
||||||
|
if let Some(punct) = input.parse()? {
|
||||||
|
punctuated.push_punct(punct);
|
||||||
|
} else {
|
||||||
|
return Ok(Self {
|
||||||
|
base_ver,
|
||||||
|
versions: Some((seperator, punctuated)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(Self {
|
||||||
|
base_ver,
|
||||||
|
versions: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RmcStructAttr {
|
||||||
|
fn versions(&self) -> impl Iterator<Item = &RmcStructAttrVersion> {
|
||||||
|
self.versions.iter().flat_map(|v| v.1.iter())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for RmcStructAttrVersion {
|
||||||
|
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||||
|
let content;
|
||||||
|
let bracket = bracketed!(content in input);
|
||||||
|
let (feature_name, delim, struct_version) =
|
||||||
|
content.call(|s| Ok((s.parse()?, s.parse()?, s.parse()?)))?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
bracket,
|
||||||
|
delim,
|
||||||
|
feature_name,
|
||||||
|
struct_version,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_write_size_struct(
|
||||||
|
s: &DataStruct,
|
||||||
|
with_potential_header: bool,
|
||||||
|
) -> proc_macro2::TokenStream {
|
||||||
|
// this is fine and works because of a quirk where the sizes of the structs dont change
|
||||||
|
// if we ignore wether or not a struct extends the other struct or has it as a field
|
||||||
|
|
||||||
|
let base_size = fold_tokenable(s.fields.iter().map(|f| {
|
||||||
|
let ident = f.ident.as_ref().unwrap();
|
||||||
|
let attrs = fold_tokenable(f.attrs.iter().filter(|a| {
|
||||||
|
if let Some(i) = a.meta.path().get_ident() {
|
||||||
|
i.to_string() != "extends"
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
quote! {
|
||||||
|
#attrs
|
||||||
|
sum += rnex_core::rmc::structures::RmcSerialize::serialize_write_size(&self.#ident)?;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
let optional_struct_header_calc = if with_potential_header {
|
||||||
|
quote! { sum += (if rnex_core::config::FEATURE_HAS_STRUCT_HEADER{ 5 } else { 0 }); }
|
||||||
|
} else {
|
||||||
|
quote! {}
|
||||||
|
};
|
||||||
|
quote! {
|
||||||
|
let mut sum = 0;
|
||||||
|
#base_size
|
||||||
|
#optional_struct_header_calc
|
||||||
|
Ok(sum)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn generate_serialize_struct(
|
||||||
|
extended_struct: Option<&Field>,
|
||||||
|
elems: &[&Field],
|
||||||
|
with_header: bool,
|
||||||
|
) -> proc_macro2::TokenStream {
|
||||||
|
fn gen_elem_serialize(f: &Field) -> TokenStream {
|
||||||
|
let ident = f.ident.as_ref().unwrap();
|
||||||
|
let attrs = fold_tokenable(f.attrs.iter().filter(|a| {
|
||||||
|
if let Some(i) = a.meta.path().get_ident() {
|
||||||
|
i.to_string() != "extends"
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
quote! {
|
||||||
|
#attrs
|
||||||
|
rnex_core::rmc::structures::RmcSerialize::serialize(&self.#ident, writer)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let optional_extended_struct = if let Some(f) = extended_struct {
|
||||||
|
gen_elem_serialize(f)
|
||||||
|
} else {
|
||||||
|
quote! {}
|
||||||
|
};
|
||||||
|
let elems = fold_tokenable(elems.iter().map(|e| gen_elem_serialize(e)));
|
||||||
|
let ser_body = if with_header {
|
||||||
|
quote! {
|
||||||
|
rnex_core::rmc::structures::rmc_struct::write_struct(
|
||||||
|
writer,
|
||||||
|
Self::version().unwrap(),
|
||||||
|
rnex_core::rmc::structures::helpers::len_of_write(
|
||||||
|
|writer|{
|
||||||
|
#elems
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
),
|
||||||
|
|writer|{
|
||||||
|
#elems
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
elems
|
||||||
|
};
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#optional_extended_struct
|
||||||
|
#ser_body
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn generate_deserialize_struct(
|
||||||
|
s: &DataStruct,
|
||||||
|
extended_struct: Option<&Field>,
|
||||||
|
elems: &[&Field],
|
||||||
|
with_header: bool,
|
||||||
|
) -> proc_macro2::TokenStream {
|
||||||
|
fn gen_elem_serialize(f: &Field) -> TokenStream {
|
||||||
|
let ident = f.ident.as_ref().unwrap();
|
||||||
|
let ty = &f.ty;
|
||||||
|
let attrs = fold_tokenable(f.attrs.iter().filter(|a| {
|
||||||
|
if let Some(i) = a.meta.path().get_ident() {
|
||||||
|
i.to_string() != "extends"
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
quote! {
|
||||||
|
#attrs
|
||||||
|
let #ident: #ty = rnex_core::rmc::structures::RmcSerialize::deserialize(reader)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let optional_extended_struct = if let Some(f) = extended_struct {
|
||||||
|
gen_elem_serialize(f)
|
||||||
|
} else {
|
||||||
|
quote! {}
|
||||||
|
};
|
||||||
|
let elems = fold_tokenable(elems.iter().map(|e| gen_elem_serialize(e)));
|
||||||
|
let struct_ctor_content = fold_tokenable(s.fields.iter().map(|f| {
|
||||||
|
let ident = f.ident.as_ref().unwrap();
|
||||||
|
let attrs = fold_tokenable(f.attrs.iter().filter(|a| {
|
||||||
|
if let Some(i) = a.meta.path().get_ident() {
|
||||||
|
i.to_string() != "extends"
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
quote! { #attrs #ident, }
|
||||||
|
}));
|
||||||
|
let de_body_inner = quote! {
|
||||||
|
#elems
|
||||||
|
Ok(Self{
|
||||||
|
#struct_ctor_content
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let de_body = if with_header {
|
||||||
|
quote! {
|
||||||
|
Ok(rnex_core::rmc::structures::rmc_struct::read_struct(reader, Self::version().unwrap(), move |mut reader|{
|
||||||
|
#de_body_inner
|
||||||
|
})?)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
de_body_inner
|
||||||
|
};
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#optional_extended_struct
|
||||||
|
#de_body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_struct_version(attr: Option<&RmcStructAttr>) -> proc_macro2::TokenStream {
|
||||||
|
if let Some(attr) = attr {
|
||||||
|
let base_ver = &attr.base_ver;
|
||||||
|
let if_else_chain = fold_tokenable(attr.versions().map(|v| {
|
||||||
|
let version_val = &v.struct_version;
|
||||||
|
let feature = &v.feature_name;
|
||||||
|
quote! {
|
||||||
|
if cfg!(feature = #feature){
|
||||||
|
#version_val
|
||||||
|
} else
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
Some(#if_else_chain {
|
||||||
|
#base_ver
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! { None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rmc_serialize_struct(
|
||||||
|
s: &DataStruct,
|
||||||
|
derive_input: &DeriveInput,
|
||||||
|
) -> (
|
||||||
|
proc_macro2::TokenStream,
|
||||||
|
proc_macro2::TokenStream,
|
||||||
|
Option<proc_macro2::TokenStream>,
|
||||||
|
Option<proc_macro2::TokenStream>,
|
||||||
|
) {
|
||||||
|
let struct_attr = derive_input.attrs.iter().find(|a| {
|
||||||
|
a.path().segments.len() == 1
|
||||||
|
&& a.path()
|
||||||
|
.segments
|
||||||
|
.first()
|
||||||
|
.is_some_and(|p| p.ident.to_string() == "rmc_struct")
|
||||||
|
&& matches!(a.meta, Meta::List(_))
|
||||||
|
});
|
||||||
|
|
||||||
|
let struct_attr: Option<RmcStructAttr> = struct_attr.map(|a| a.parse_args().unwrap());
|
||||||
|
let struct_attr = struct_attr.as_ref();
|
||||||
|
|
||||||
|
let extended_struct = s.fields.iter().find(|f| {
|
||||||
|
f.attrs.iter().any(|a| {
|
||||||
|
a.path().segments.len() == 1
|
||||||
|
&& a.path()
|
||||||
|
.segments
|
||||||
|
.first()
|
||||||
|
.is_some_and(|p| p.ident.to_string() == "extends")
|
||||||
|
})
|
||||||
|
});
|
||||||
|
let elements: Vec<_> = s
|
||||||
|
.fields
|
||||||
|
.iter()
|
||||||
|
.filter(|f| {
|
||||||
|
!f.attrs.iter().any(|a| {
|
||||||
|
a.path().segments.len() == 1
|
||||||
|
&& a.path()
|
||||||
|
.segments
|
||||||
|
.first()
|
||||||
|
.is_some_and(|p| p.ident.to_string() == "extends")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let elements = &elements[..];
|
||||||
|
|
||||||
|
let serialize = generate_serialize_struct(extended_struct, elements, struct_attr.is_some());
|
||||||
|
let deserialize =
|
||||||
|
generate_deserialize_struct(s, extended_struct, elements, struct_attr.is_some());
|
||||||
|
let write_size = generate_write_size_struct(s, struct_attr.is_some());
|
||||||
|
let version = generate_struct_version(struct_attr);
|
||||||
|
|
||||||
|
(serialize, deserialize, Some(write_size), Some(version))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn field_to_ident(field: &Field, idx: usize) -> Ident {
|
||||||
|
if let Some(i) = &field.ident {
|
||||||
|
i.clone()
|
||||||
|
} else {
|
||||||
|
Ident::new(&format!("field_{}", idx), Span::call_site())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn variant_to_pattern_and_fields(variant: &Variant) -> (proc_macro2::TokenStream, Vec<Field>) {
|
||||||
|
match &variant.fields {
|
||||||
|
Fields::Named(n) => {
|
||||||
|
let inner = n
|
||||||
|
.named
|
||||||
|
.iter()
|
||||||
|
.map(|f| {
|
||||||
|
let attrs = fold_tokenable(f.attrs.iter());
|
||||||
|
let ident = f.ident.as_ref().unwrap();
|
||||||
|
|
||||||
|
quote! { #attrs #ident }
|
||||||
|
})
|
||||||
|
.reduce(|a, b| quote! {#a, #b});
|
||||||
|
|
||||||
|
(quote! {{#inner}}, n.named.iter().cloned().collect())
|
||||||
|
}
|
||||||
|
Fields::Unnamed(n) => {
|
||||||
|
let inner = n
|
||||||
|
.unnamed
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, f)| {
|
||||||
|
let attrs = fold_tokenable(f.attrs.iter());
|
||||||
|
let name = field_to_ident(f, i);
|
||||||
|
|
||||||
|
quote! { #attrs #name }
|
||||||
|
})
|
||||||
|
.reduce(|a, b| quote! {#a, #b});
|
||||||
|
|
||||||
|
(quote! {(#inner)}, n.unnamed.iter().cloned().collect())
|
||||||
|
}
|
||||||
|
Fields::Unit => (quote! {}, vec![]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rmc_generate_serialize_enum(
|
||||||
|
enum_data: &DataEnum,
|
||||||
|
repr_ty: &Ident,
|
||||||
|
) -> proc_macro2::TokenStream {
|
||||||
|
let match_content = fold_tokenable(enum_data.variants.iter().map(|v|{
|
||||||
|
let ident = &v.ident;
|
||||||
|
let descriminant = &v.discriminant.as_ref().expect("every variant must have a descriminant to be a valid rmc struct").1;
|
||||||
|
let (pattern, fields) = variant_to_pattern_and_fields(v);
|
||||||
|
let inner = fold_tokenable(fields.iter().enumerate().map(|(i, f)|{
|
||||||
|
let ty = &f.ty;
|
||||||
|
let name = field_to_ident(&f, i);
|
||||||
|
quote! {<#ty as rnex_core::rmc::structures::RmcSerialize>::serialize(#name, writer)?;}
|
||||||
|
}));
|
||||||
|
quote!{
|
||||||
|
Self::#ident #pattern => {
|
||||||
|
<#repr_ty as rnex_core::rmc::structures::RmcSerialize>::serialize(&#descriminant, writer)?;
|
||||||
|
#inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
quote! {
|
||||||
|
match self{
|
||||||
|
#match_content
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn rmc_generate_deserialize_enum(
|
||||||
|
enum_data: &DataEnum,
|
||||||
|
repr_ty: &Ident,
|
||||||
|
) -> proc_macro2::TokenStream {
|
||||||
|
let match_content = fold_tokenable(enum_data.variants.iter().map(|v| {
|
||||||
|
let ident = &v.ident;
|
||||||
|
let descriminant = &v
|
||||||
|
.discriminant
|
||||||
|
.as_ref()
|
||||||
|
.expect("every variant must have a descriminant to be a valid rmc struct")
|
||||||
|
.1;
|
||||||
|
let (pattern, fields) = variant_to_pattern_and_fields(v);
|
||||||
|
let inner = fold_tokenable(fields.iter().enumerate().map(|(i, f)| {
|
||||||
|
let ty = &f.ty;
|
||||||
|
let name = field_to_ident(&f, i);
|
||||||
|
quote! {let #name = <#ty as rnex_core::rmc::structures::RmcSerialize>::deserialize(reader)?;}
|
||||||
|
}));
|
||||||
|
quote! {
|
||||||
|
#descriminant => {
|
||||||
|
#inner
|
||||||
|
|
||||||
|
Self::#ident #pattern
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
let discriminant = <#repr_ty as rnex_core::rmc::structures::RmcSerialize>::deserialize(reader)?;
|
||||||
|
|
||||||
|
Ok(match discriminant{
|
||||||
|
#match_content
|
||||||
|
v => {
|
||||||
|
return Err(rnex_core::rmc::structures::Error::UnexpectedValue(v as u64))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rmc_serialize_enum(
|
||||||
|
enum_data: &DataEnum,
|
||||||
|
derive_input: &DeriveInput,
|
||||||
|
) -> (
|
||||||
|
proc_macro2::TokenStream,
|
||||||
|
proc_macro2::TokenStream,
|
||||||
|
Option<proc_macro2::TokenStream>,
|
||||||
|
Option<proc_macro2::TokenStream>,
|
||||||
|
) {
|
||||||
|
let repr_attr = derive_input.attrs.iter().find(|a| {
|
||||||
|
a.path().segments.len() == 1
|
||||||
|
&& a.path()
|
||||||
|
.segments
|
||||||
|
.first()
|
||||||
|
.is_some_and(|p| p.ident.to_string() == "repr")
|
||||||
|
});
|
||||||
|
let Some(repr_attr) = repr_attr else {
|
||||||
|
panic!("missing repr attribute");
|
||||||
|
};
|
||||||
|
|
||||||
|
let ty: Ident = repr_attr.parse_args().unwrap();
|
||||||
|
|
||||||
|
let serialize = rmc_generate_serialize_enum(&enum_data, &ty);
|
||||||
|
let deserialize = rmc_generate_deserialize_enum(&enum_data, &ty);
|
||||||
|
|
||||||
|
(serialize, deserialize, None, None)
|
||||||
|
}
|
||||||
10
macros/src/util.rs
Normal file
10
macros/src/util.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::ToTokens;
|
||||||
|
|
||||||
|
// todo: return a wrapper struct implementing ToTokens over the iterator instead as to avoid unnescesary allocations with the token stream
|
||||||
|
pub fn fold_tokenable<T: ToTokens>(list: impl Iterator<Item = T>) -> TokenStream {
|
||||||
|
list.fold(TokenStream::new(), |mut s, i| {
|
||||||
|
i.to_tokens(&mut s);
|
||||||
|
s
|
||||||
|
})
|
||||||
|
}
|
||||||
Binary file not shown.
BIN
perf.data
BIN
perf.data
Binary file not shown.
|
|
@ -1,12 +1,12 @@
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use rnex_core::{
|
use rnex_core::{
|
||||||
PID,
|
PID,
|
||||||
executables::common::{OWN_IP_PUBLIC, try_get_ip},
|
executables::common::try_get_ip,
|
||||||
prudp::{socket_addr::PRUDPSockAddr, virtual_port::VirtualPort},
|
prudp::{socket_addr::PRUDPSockAddr, virtual_port::VirtualPort},
|
||||||
reggie::{RemoteEdgeNodeHolder, UnitPacketWrite},
|
reggie::{RemoteEdgeNodeHolder, UnitPacketWrite},
|
||||||
rmc::{
|
rmc::{
|
||||||
protocols::{
|
protocols::{
|
||||||
OnlyRemote, RemoteDisconnectable, RmcCallable, RmcConnection, RmcPureRemoteObject,
|
RemoteDisconnectable, RmcCallable, RmcConnection, RmcPureRemoteObject,
|
||||||
new_rmc_gateway_connection,
|
new_rmc_gateway_connection,
|
||||||
},
|
},
|
||||||
structures::RmcSerialize,
|
structures::RmcSerialize,
|
||||||
|
|
@ -17,7 +17,7 @@ use rnex_core::{
|
||||||
use std::{
|
use std::{
|
||||||
env::{self, VarError},
|
env::{self, VarError},
|
||||||
error,
|
error,
|
||||||
net::{AddrParseError, IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4},
|
net::{AddrParseError, Ipv4Addr, SocketAddr, SocketAddrV4},
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
panic,
|
panic,
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
|
|
@ -75,6 +75,7 @@ const VIRTUAL_PORT_INSECURE: LazyLock<VirtualPort> =
|
||||||
const VIRTUAL_PORT_SECURE: LazyLock<VirtualPort> =
|
const VIRTUAL_PORT_SECURE: LazyLock<VirtualPort> =
|
||||||
LazyLock::new(|| VirtualPort::parse(env!("RNEX_VIRTUAL_PORT_SECURE")).unwrap());
|
LazyLock::new(|| VirtualPort::parse(env!("RNEX_VIRTUAL_PORT_SECURE")).unwrap());
|
||||||
impl ProxyStartupParam {
|
impl ProxyStartupParam {
|
||||||
|
#[inline(always)]
|
||||||
pub fn new(prox_ty: ProxyType) -> Result<Self, Error> {
|
pub fn new(prox_ty: ProxyType) -> Result<Self, Error> {
|
||||||
let port = RNEX_DEFAULT_PORT
|
let port = RNEX_DEFAULT_PORT
|
||||||
+ match prox_ty {
|
+ match prox_ty {
|
||||||
|
|
@ -82,7 +83,7 @@ impl ProxyStartupParam {
|
||||||
ProxyType::Secure => 1,
|
ProxyType::Secure => 1,
|
||||||
};
|
};
|
||||||
let self_private = try_get_env("SERVER_IP_PRIVATE")
|
let self_private = try_get_env("SERVER_IP_PRIVATE")
|
||||||
.unwrap_or(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, RNEX_DEFAULT_PORT));
|
.unwrap_or(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, port));
|
||||||
let self_public: SocketAddrV4 = match try_get_env("SERVER_IP_PUBLIC") {
|
let self_public: SocketAddrV4 = match try_get_env("SERVER_IP_PUBLIC") {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => try_get_ip()
|
Err(e) => try_get_ip()
|
||||||
|
|
@ -121,6 +122,7 @@ impl<T: RemoteDisconnectable + RmcPureRemoteObject, C: FnOnce() + Send + Sync +
|
||||||
Self(T::new(conn), Some(drop_func))
|
Self(T::new(conn), Some(drop_func))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub async fn disconnect(&self) {
|
pub async fn disconnect(&self) {
|
||||||
self.0.disconnect().await;
|
self.0.disconnect().await;
|
||||||
}
|
}
|
||||||
|
|
@ -208,6 +210,7 @@ pub async fn new_backend_connection(
|
||||||
mod test {
|
mod test {
|
||||||
use crate::{VIRTUAL_PORT_INSECURE, VIRTUAL_PORT_SECURE};
|
use crate::{VIRTUAL_PORT_INSECURE, VIRTUAL_PORT_SECURE};
|
||||||
|
|
||||||
|
#[test]
|
||||||
fn test_virtual_port_correct() {
|
fn test_virtual_port_correct() {
|
||||||
println!("{:?}", VIRTUAL_PORT_INSECURE);
|
println!("{:?}", VIRTUAL_PORT_INSECURE);
|
||||||
println!("{:?}", VIRTUAL_PORT_SECURE);
|
println!("{:?}", VIRTUAL_PORT_SECURE);
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use crate::crypto::Crypto;
|
||||||
pub struct Insecure;
|
pub struct Insecure;
|
||||||
|
|
||||||
impl Crypto for Insecure {
|
impl Crypto for Insecure {
|
||||||
fn new_connection(&self, data: &[u8]) -> Option<(PID, Vec<u8>)> {
|
fn new_connection(&self, _data: &[u8]) -> Option<(PID, Vec<u8>)> {
|
||||||
Some((100, vec![]))
|
Some((100, vec![]))
|
||||||
}
|
}
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ use rnex_core::{
|
||||||
types_flags::{
|
types_flags::{
|
||||||
TypesFlags,
|
TypesFlags,
|
||||||
flags::{ACK, NEED_ACK, RELIABLE},
|
flags::{ACK, NEED_ACK, RELIABLE},
|
||||||
types::{CONNECT, DATA, DISCONNECT, SYN},
|
types::{CONNECT, DATA, DISCONNECT, PING, SYN},
|
||||||
},
|
},
|
||||||
virtual_port::VirtualPort,
|
virtual_port::VirtualPort,
|
||||||
},
|
},
|
||||||
|
|
@ -26,20 +26,20 @@ use rnex_core::{
|
||||||
use tokio::net::{TcpListener, TcpStream};
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
use tokio_tungstenite::{
|
use tokio_tungstenite::{
|
||||||
WebSocketStream,
|
WebSocketStream,
|
||||||
tungstenite::{
|
tungstenite::{Bytes, Message},
|
||||||
Bytes, Message, client::IntoClientRequest, http::header::ACCESS_CONTROL_REQUEST_METHOD,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ConnectionState {
|
struct ConnectionState {
|
||||||
param: Arc<ProxyStartupParam>,
|
param: Arc<ProxyStartupParam>,
|
||||||
active: bool,
|
active: bool,
|
||||||
websocket: WebSocketStream<TcpStream>,
|
websocket: WebSocketStream<TcpStream>,
|
||||||
|
#[allow(dead_code)]
|
||||||
pid: PID,
|
pid: PID,
|
||||||
backend_conn: SplittableBufferConnection,
|
backend_conn: SplittableBufferConnection,
|
||||||
addr: PRUDPSockAddr,
|
addr: PRUDPSockAddr,
|
||||||
incoming_reliable: HashMap<u16, LitePacket<Bytes>>,
|
incoming_reliable: HashMap<u16, LitePacket<Bytes>>,
|
||||||
client_reliable_counter: u16,
|
client_reliable_counter: u16,
|
||||||
|
#[allow(dead_code)]
|
||||||
server_reliable_counter: u16,
|
server_reliable_counter: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,10 +71,16 @@ impl ConnectionState {
|
||||||
);
|
);
|
||||||
let data: Bytes = data.into();
|
let data: Bytes = data.into();
|
||||||
if header.types_flags.get_types() == DISCONNECT {
|
if header.types_flags.get_types() == DISCONNECT {
|
||||||
self.websocket.send(Message::Binary(data.clone())).await;
|
self.websocket
|
||||||
self.websocket.send(Message::Binary(data.clone())).await;
|
.send(Message::Binary(data.clone()))
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
|
self.websocket
|
||||||
|
.send(Message::Binary(data.clone()))
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
self.websocket.send(Message::Binary(data)).await;
|
self.websocket.send(Message::Binary(data)).await.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.types_flags.get_flags() & ACK) != 0 {
|
if (header.types_flags.get_flags() & ACK) != 0 {
|
||||||
|
|
@ -111,6 +117,7 @@ impl ConnectionState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[allow(dead_code)]
|
||||||
pub async fn process_reliable(&mut self) {
|
pub async fn process_reliable(&mut self) {
|
||||||
while let Some(v) = self.incoming_reliable.remove(&self.client_reliable_counter) {
|
while let Some(v) = self.incoming_reliable.remove(&self.client_reliable_counter) {
|
||||||
self.handle_incoming_prudp(v, true).await;
|
self.handle_incoming_prudp(v, true).await;
|
||||||
|
|
@ -131,7 +138,7 @@ impl ConnectionState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
v = self.backend_conn.recv() => {
|
_ = self.backend_conn.recv() => {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -197,7 +204,7 @@ pub async fn websocket_thread_unconnected<C: Crypto>(
|
||||||
],
|
],
|
||||||
&[],
|
&[],
|
||||||
);
|
);
|
||||||
websocket.send(Message::Binary(data.into())).await;
|
websocket.send(Message::Binary(data.into())).await.ok();
|
||||||
}
|
}
|
||||||
CONNECT => {
|
CONNECT => {
|
||||||
let Some(supported) = packet.packet_specific_iter() else {
|
let Some(supported) = packet.packet_specific_iter() else {
|
||||||
|
|
@ -242,7 +249,7 @@ pub async fn websocket_thread_unconnected<C: Crypto>(
|
||||||
],
|
],
|
||||||
&data,
|
&data,
|
||||||
);
|
);
|
||||||
websocket.send(Message::Binary(data.into())).await;
|
websocket.send(Message::Binary(data.into())).await.ok();
|
||||||
|
|
||||||
let addr = PRUDPSockAddr::new(
|
let addr = PRUDPSockAddr::new(
|
||||||
addr,
|
addr,
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,7 @@ use std::{
|
||||||
io::{self, Cursor, Read, Write},
|
io::{self, Cursor, Read, Write},
|
||||||
};
|
};
|
||||||
|
|
||||||
use bytemuck::{Pod, Zeroable, bytes_of};
|
use bytemuck::{Pod, Zeroable, bytes_of_mut};
|
||||||
use futures_util::Stream;
|
|
||||||
use rnex_core::prudp::types_flags::TypesFlags;
|
use rnex_core::prudp::types_flags::TypesFlags;
|
||||||
use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions};
|
use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions};
|
||||||
|
|
||||||
|
|
@ -30,10 +29,10 @@ pub enum PacketSpecificData {
|
||||||
|
|
||||||
impl PacketSpecificData {
|
impl PacketSpecificData {
|
||||||
fn consume(reader: &mut impl Read) -> io::Result<Self> {
|
fn consume(reader: &mut impl Read) -> io::Result<Self> {
|
||||||
let mut option_id = 0;
|
let mut option_id = 0u8;
|
||||||
reader.read_exact(&mut [option_id])?;
|
reader.read_exact(bytes_of_mut(&mut option_id))?;
|
||||||
let mut size = 0;
|
let mut size = 0u8;
|
||||||
reader.read_exact(&mut [size])?;
|
reader.read_exact(bytes_of_mut(&mut size))?;
|
||||||
|
|
||||||
match option_id {
|
match option_id {
|
||||||
0 => {
|
0 => {
|
||||||
|
|
@ -156,7 +155,7 @@ impl<T: AsRef<[u8]>> LitePacket<T> {
|
||||||
.get_mut(size_of::<LiteHeader>()..size_of::<LiteHeader>() + len as usize)
|
.get_mut(size_of::<LiteHeader>()..size_of::<LiteHeader>() + len as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn packet_specific_iter(&self) -> Option<PacketSpecificIter> {
|
pub fn packet_specific_iter<'a>(&'a self) -> Option<PacketSpecificIter<'a>> {
|
||||||
self.packet_specific_raw()
|
self.packet_specific_raw()
|
||||||
.map(Cursor::new)
|
.map(Cursor::new)
|
||||||
.map(PacketSpecificIter)
|
.map(PacketSpecificIter)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{io::Write, rc::Rc};
|
use std::io::Write;
|
||||||
|
|
||||||
use hmac::Mac;
|
use hmac::Mac;
|
||||||
use md5::{Digest, Md5};
|
use md5::{Digest, Md5};
|
||||||
|
|
@ -18,6 +18,7 @@ use crate::crypto::{
|
||||||
pub struct InsecureInstance {
|
pub struct InsecureInstance {
|
||||||
pair: EncryptionPair<Rc4<U5>>,
|
pair: EncryptionPair<Rc4<U5>>,
|
||||||
self_signat: [u8; 4],
|
self_signat: [u8; 4],
|
||||||
|
#[allow(dead_code)]
|
||||||
remote_signat: [u8; 4],
|
remote_signat: [u8; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,7 +63,7 @@ impl Crypto for Insecure {
|
||||||
|
|
||||||
fn instantiate(
|
fn instantiate(
|
||||||
&self,
|
&self,
|
||||||
packet_data: &[u8],
|
_packet_data: &[u8],
|
||||||
self_signat: [u8; 4],
|
self_signat: [u8; 4],
|
||||||
remote_signat: [u8; 4],
|
remote_signat: [u8; 4],
|
||||||
) -> Option<(Self::Instance, Vec<u8>)> {
|
) -> Option<(Self::Instance, Vec<u8>)> {
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ pub struct SecureInstance {
|
||||||
pair: EncryptionPair<Rc4<U16>>,
|
pair: EncryptionPair<Rc4<U16>>,
|
||||||
uid: u32,
|
uid: u32,
|
||||||
self_signat: [u8; 4],
|
self_signat: [u8; 4],
|
||||||
|
#[allow(dead_code)]
|
||||||
remote_signat: [u8; 4],
|
remote_signat: [u8; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,13 @@
|
||||||
cfg_if::cfg_if! {
|
use cfg_if::cfg_if;
|
||||||
|
cfg_if! {
|
||||||
if #[cfg(feature = "prudpv0")] {
|
if #[cfg(feature = "prudpv0")] {
|
||||||
use bytemuck::{Pod, Zeroable};
|
use log::info;
|
||||||
use cfg_if::cfg_if;
|
use proxy_common::ProxyStartupParam;
|
||||||
use log::{error, info, warn};
|
|
||||||
use proxy_common::{ProxyStartupParam, setup_edge_node_connection};
|
|
||||||
use rnex_core::executables::common::{OWN_IP_PRIVATE, OWN_IP_PUBLIC, SERVER_PORT};
|
|
||||||
use rnex_core::prudp::types_flags::TypesFlags;
|
|
||||||
use rnex_core::prudp::types_flags::types::SYN;
|
|
||||||
use rnex_core::prudp::virtual_port::VirtualPort;
|
|
||||||
use rnex_core::reggie::EdgeNodeHolderConnectOption::Register;
|
|
||||||
use rnex_core::reggie::RemoteEdgeNodeHolder;
|
|
||||||
use rnex_core::rmc::protocols::{OnlyRemote, new_rmc_gateway_connection};
|
|
||||||
use rnex_core::rmc::structures::RmcSerialize;
|
|
||||||
use rnex_core::util::SplittableBufferConnection;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::net::SocketAddrV4;
|
use std::net::SocketAddrV4;
|
||||||
use std::process::abort;
|
|
||||||
use std::sync::{Arc, LazyLock};
|
use std::sync::{Arc, LazyLock};
|
||||||
use tokio::net::UdpSocket;
|
|
||||||
|
|
||||||
use crate::crypto::{Crypto, Insecure, Secure};
|
use crate::crypto::{Crypto, Insecure, Secure};
|
||||||
use crate::packet::PRUDPV0Packet;
|
|
||||||
use crate::server::Server;
|
use crate::server::Server;
|
||||||
|
|
||||||
mod crypto;
|
mod crypto;
|
||||||
|
|
@ -44,8 +31,6 @@ cfg_if::cfg_if! {
|
||||||
//implementations, e.g. secure and insecure(this also includes special cases like friends)
|
//implementations, e.g. secure and insecure(this also includes special cases like friends)
|
||||||
|
|
||||||
async fn start_proxy<T: Crypto>(param: ProxyStartupParam) {
|
async fn start_proxy<T: Crypto>(param: ProxyStartupParam) {
|
||||||
info!("creating cryptography instance");
|
|
||||||
let mut crypto = Arc::new(T::new());
|
|
||||||
info!("binding to socket");
|
info!("binding to socket");
|
||||||
|
|
||||||
let server: Arc<Server<T>> = Arc::new(Server::new(param).await);
|
let server: Arc<Server<T>> = Arc::new(Server::new(param).await);
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
use std::mem::transmute;
|
|
||||||
|
|
||||||
use bytemuck::{Pod, Zeroable, try_from_bytes, try_from_bytes_mut};
|
use bytemuck::{Pod, Zeroable, try_from_bytes, try_from_bytes_mut};
|
||||||
use log::{error, info, warn};
|
use log::{info, warn};
|
||||||
use rnex_core::prudp::{
|
use rnex_core::prudp::{
|
||||||
types_flags::{
|
types_flags::{
|
||||||
self, TypesFlags,
|
TypesFlags,
|
||||||
flags::{HAS_SIZE, NEED_ACK},
|
flags::HAS_SIZE,
|
||||||
types::{CONNECT, DATA, DISCONNECT, PING, SYN},
|
types::{CONNECT, DATA, DISCONNECT, PING, SYN},
|
||||||
},
|
},
|
||||||
virtual_port::VirtualPort,
|
virtual_port::VirtualPort,
|
||||||
|
|
@ -165,6 +163,7 @@ impl<T: AsRef<[u8]>> PRUDPV0Packet<T> {
|
||||||
|
|
||||||
const DEFAULT_SIGNAT: [u8; 4] = [0x12, 0x34, 0x56, 0x78];
|
const DEFAULT_SIGNAT: [u8; 4] = [0x12, 0x34, 0x56, 0x78];
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[allow(dead_code)]
|
||||||
const fn get_size_offset(tf: TypesFlags) -> usize {
|
const fn get_size_offset(tf: TypesFlags) -> usize {
|
||||||
size_of::<PRUDPV0Header>()
|
size_of::<PRUDPV0Header>()
|
||||||
+ (if tf.get_types() & (SYN | CONNECT) != 0 {
|
+ (if tf.get_types() & (SYN | CONNECT) != 0 {
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,24 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
hash::Hash,
|
net::{SocketAddr, SocketAddrV4},
|
||||||
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
|
sync::{Arc, Weak},
|
||||||
sync::{
|
|
||||||
Arc, LazyLock, Weak,
|
|
||||||
atomic::{AtomicBool, AtomicU32},
|
|
||||||
},
|
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use proxy_common::{ProxyStartupParam, new_backend_connection};
|
use proxy_common::{ProxyStartupParam, new_backend_connection};
|
||||||
use rnex_core::{
|
use rnex_core::{
|
||||||
executables::common::{OWN_IP_PRIVATE, SERVER_PORT},
|
|
||||||
prudp::{
|
prudp::{
|
||||||
socket_addr::PRUDPSockAddr,
|
socket_addr::PRUDPSockAddr,
|
||||||
types_flags::{
|
types_flags::{
|
||||||
TypesFlags,
|
flags::{ACK, NEED_ACK, RELIABLE},
|
||||||
flags::{ACK, HAS_SIZE, NEED_ACK, RELIABLE},
|
|
||||||
types::{CONNECT, DATA, DISCONNECT, PING, SYN},
|
types::{CONNECT, DATA, DISCONNECT, PING, SYN},
|
||||||
},
|
},
|
||||||
virtual_port::VirtualPort,
|
|
||||||
},
|
},
|
||||||
rnex_proxy_common::ConnectionInitData,
|
|
||||||
util::{SendingBufferConnection, SplittableBufferConnection},
|
util::{SendingBufferConnection, SplittableBufferConnection},
|
||||||
};
|
};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
net::{TcpSocket, UdpSocket},
|
net::UdpSocket,
|
||||||
spawn,
|
spawn,
|
||||||
sync::{Mutex, RwLock},
|
sync::{Mutex, RwLock},
|
||||||
time::{Instant, sleep},
|
time::{Instant, sleep},
|
||||||
|
|
@ -35,8 +27,8 @@ use tokio::{
|
||||||
use crate::{
|
use crate::{
|
||||||
crypto::{Crypto, CryptoInstance},
|
crypto::{Crypto, CryptoInstance},
|
||||||
packet::{
|
packet::{
|
||||||
PRUDPV0Header, PRUDPV0Packet, new_connect_packet, new_data_packet, new_disconnect_packet,
|
PRUDPV0Packet, new_connect_packet, new_data_packet, new_disconnect_packet, new_ping_packet,
|
||||||
new_ping_packet, new_syn_packet, precalc_size,
|
new_syn_packet,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -49,16 +41,14 @@ pub struct InternalConnection<C: CryptoInstance> {
|
||||||
packet_queue: HashMap<u16, (Instant, PRUDPV0Packet<Vec<u8>>)>,
|
packet_queue: HashMap<u16, (Instant, PRUDPV0Packet<Vec<u8>>)>,
|
||||||
}
|
}
|
||||||
pub struct Connection<C: CryptoInstance> {
|
pub struct Connection<C: CryptoInstance> {
|
||||||
alive: AtomicBool,
|
|
||||||
session_id: u8,
|
session_id: u8,
|
||||||
target: SendingBufferConnection,
|
target: SendingBufferConnection,
|
||||||
self_signat: [u8; 4],
|
|
||||||
remote_signat: [u8; 4],
|
|
||||||
addr: PRUDPSockAddr,
|
addr: PRUDPSockAddr,
|
||||||
inner: Mutex<InternalConnection<C>>,
|
inner: Mutex<InternalConnection<C>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: CryptoInstance> InternalConnection<C> {
|
impl<C: CryptoInstance> InternalConnection<C> {
|
||||||
|
#[allow(dead_code)]
|
||||||
fn next_server_count(&mut self) -> u16 {
|
fn next_server_count(&mut self) -> u16 {
|
||||||
let prev_val = self.server_packet_counter;
|
let prev_val = self.server_packet_counter;
|
||||||
let (val, _) = self.server_packet_counter.overflowing_add(1);
|
let (val, _) = self.server_packet_counter.overflowing_add(1);
|
||||||
|
|
@ -148,7 +138,8 @@ impl<C: Crypto> Server<C> {
|
||||||
|
|
||||||
this.socket
|
this.socket
|
||||||
.send_to(&data, conn.addr.regular_socket_addr)
|
.send_to(&data, conn.addr.regular_socket_addr)
|
||||||
.await;
|
.await
|
||||||
|
.ok();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -192,7 +183,8 @@ impl<C: Crypto> Server<C> {
|
||||||
|
|
||||||
self.socket
|
self.socket
|
||||||
.send_to(&packet, conn.addr.regular_socket_addr)
|
.send_to(&packet, conn.addr.regular_socket_addr)
|
||||||
.await;
|
.await
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Instant::now() - inner.last_action).as_secs() > 15 {
|
if (Instant::now() - inner.last_action).as_secs() > 15 {
|
||||||
|
|
@ -210,13 +202,16 @@ impl<C: Crypto> Server<C> {
|
||||||
|
|
||||||
self.socket
|
self.socket
|
||||||
.send_to(&packet, conn.addr.regular_socket_addr)
|
.send_to(&packet, conn.addr.regular_socket_addr)
|
||||||
.await;
|
.await
|
||||||
|
.ok();
|
||||||
self.socket
|
self.socket
|
||||||
.send_to(&packet, conn.addr.regular_socket_addr)
|
.send_to(&packet, conn.addr.regular_socket_addr)
|
||||||
.await;
|
.await
|
||||||
|
.ok();
|
||||||
self.socket
|
self.socket
|
||||||
.send_to(&packet, conn.addr.regular_socket_addr)
|
.send_to(&packet, conn.addr.regular_socket_addr)
|
||||||
.await;
|
.await
|
||||||
|
.ok();
|
||||||
drop(inner);
|
drop(inner);
|
||||||
|
|
||||||
let mut conns = self.connections.write().await;
|
let mut conns = self.connections.write().await;
|
||||||
|
|
@ -236,7 +231,10 @@ impl<C: Crypto> Server<C> {
|
||||||
let signat = [signat[0], signat[1], signat[2], signat[3]];
|
let signat = [signat[0], signat[1], signat[2], signat[3]];
|
||||||
|
|
||||||
let packet = new_syn_packet(ACK, header.destination, header.source, signat, &self.crypto);
|
let packet = new_syn_packet(ACK, header.destination, header.source, signat, &self.crypto);
|
||||||
self.socket.send_to(&packet, addr.regular_socket_addr).await;
|
self.socket
|
||||||
|
.send_to(&packet, addr.regular_socket_addr)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
async fn handle_connect(self: Arc<Self>, packet: PRUDPV0Packet<Vec<u8>>, addr: PRUDPSockAddr) {
|
async fn handle_connect(self: Arc<Self>, packet: PRUDPV0Packet<Vec<u8>>, addr: PRUDPSockAddr) {
|
||||||
let Some(data) = packet.payload() else {
|
let Some(data) = packet.payload() else {
|
||||||
|
|
@ -275,11 +273,8 @@ impl<C: Crypto> Server<C> {
|
||||||
|
|
||||||
let conn = Arc::new(Connection {
|
let conn = Arc::new(Connection {
|
||||||
target: buf_conn.duplicate_sender(),
|
target: buf_conn.duplicate_sender(),
|
||||||
remote_signat,
|
|
||||||
self_signat,
|
|
||||||
addr,
|
addr,
|
||||||
session_id: header.session_id,
|
session_id: header.session_id,
|
||||||
alive: AtomicBool::new(true),
|
|
||||||
inner: Mutex::new(InternalConnection {
|
inner: Mutex::new(InternalConnection {
|
||||||
last_action: Instant::now(),
|
last_action: Instant::now(),
|
||||||
crypto_instance: ci,
|
crypto_instance: ci,
|
||||||
|
|
@ -320,9 +315,12 @@ impl<C: Crypto> Server<C> {
|
||||||
);
|
);
|
||||||
|
|
||||||
info!("sending back connection accept");
|
info!("sending back connection accept");
|
||||||
self.socket.send_to(&packet, addr.regular_socket_addr).await;
|
self.socket
|
||||||
|
.send_to(&packet, addr.regular_socket_addr)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
async fn handle_data(self: Arc<Self>, mut packet: PRUDPV0Packet<Vec<u8>>, addr: PRUDPSockAddr) {
|
async fn handle_data(self: Arc<Self>, packet: PRUDPV0Packet<Vec<u8>>, addr: PRUDPSockAddr) {
|
||||||
let Some(frag_id) = packet.fragment_id() else {
|
let Some(frag_id) = packet.fragment_id() else {
|
||||||
warn!("invalid packet from: {:?}", addr);
|
warn!("invalid packet from: {:?}", addr);
|
||||||
return;
|
return;
|
||||||
|
|
@ -349,7 +347,10 @@ impl<C: Crypto> Server<C> {
|
||||||
&mut conn.crypto_instance,
|
&mut conn.crypto_instance,
|
||||||
&self.crypto,
|
&self.crypto,
|
||||||
);
|
);
|
||||||
self.socket.send_to(&ack, addr.regular_socket_addr).await;
|
self.socket
|
||||||
|
.send_to(&ack, addr.regular_socket_addr)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
conn.packet_queue.insert(
|
conn.packet_queue.insert(
|
||||||
packet.header().unwrap().sequence_id,
|
packet.header().unwrap().sequence_id,
|
||||||
(Instant::now(), packet),
|
(Instant::now(), packet),
|
||||||
|
|
@ -375,7 +376,7 @@ impl<C: Crypto> Server<C> {
|
||||||
drop(conn);
|
drop(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_ping(self: Arc<Self>, mut packet: PRUDPV0Packet<Vec<u8>>, addr: PRUDPSockAddr) {
|
async fn handle_ping(self: Arc<Self>, packet: PRUDPV0Packet<Vec<u8>>, addr: PRUDPSockAddr) {
|
||||||
info!("got ping");
|
info!("got ping");
|
||||||
let header = packet.header().unwrap();
|
let header = packet.header().unwrap();
|
||||||
|
|
||||||
|
|
@ -395,11 +396,14 @@ impl<C: Crypto> Server<C> {
|
||||||
);
|
);
|
||||||
drop(inner);
|
drop(inner);
|
||||||
|
|
||||||
self.socket.send_to(&packet, addr.regular_socket_addr).await;
|
self.socket
|
||||||
|
.send_to(&packet, addr.regular_socket_addr)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
async fn handle_disconnect(
|
async fn handle_disconnect(
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
mut packet: PRUDPV0Packet<Vec<u8>>,
|
packet: PRUDPV0Packet<Vec<u8>>,
|
||||||
addr: PRUDPSockAddr,
|
addr: PRUDPSockAddr,
|
||||||
) {
|
) {
|
||||||
info!("got disconnect");
|
info!("got disconnect");
|
||||||
|
|
@ -425,9 +429,18 @@ impl<C: Crypto> Server<C> {
|
||||||
conns.remove(&(addr, header.session_id));
|
conns.remove(&(addr, header.session_id));
|
||||||
drop(conns);
|
drop(conns);
|
||||||
|
|
||||||
self.socket.send_to(&packet, addr.regular_socket_addr).await;
|
self.socket
|
||||||
self.socket.send_to(&packet, addr.regular_socket_addr).await;
|
.send_to(&packet, addr.regular_socket_addr)
|
||||||
self.socket.send_to(&packet, addr.regular_socket_addr).await;
|
.await
|
||||||
|
.ok();
|
||||||
|
self.socket
|
||||||
|
.send_to(&packet, addr.regular_socket_addr)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
|
self.socket
|
||||||
|
.send_to(&packet, addr.regular_socket_addr)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
async fn get_connection(
|
async fn get_connection(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
use std::env;
|
|
||||||
use std::net::SocketAddrV4;
|
|
||||||
|
|
||||||
pub static EDGE_NODE_HOLDER: Lazy<SocketAddrV4> = Lazy::new(|| {
|
|
||||||
env::var("EDGE_NODE_HOLDER")
|
|
||||||
.ok()
|
|
||||||
.and_then(|s| s.parse().ok())
|
|
||||||
.expect("EDGE_NODE_HOLDER not set")
|
|
||||||
});
|
|
||||||
|
|
||||||
pub static FORWARD_DESTINATION: Lazy<SocketAddrV4> = Lazy::new(|| {
|
|
||||||
env::var("FORWARD_DESTINATION")
|
|
||||||
.ok()
|
|
||||||
.and_then(|s| s.parse().ok())
|
|
||||||
.expect("FORWARD_DESTINATION not set")
|
|
||||||
});
|
|
||||||
|
|
@ -1,3 +1,2 @@
|
||||||
pub mod common;
|
|
||||||
pub mod proxy_insecure;
|
pub mod proxy_insecure;
|
||||||
pub mod proxy_secure;
|
pub mod proxy_secure;
|
||||||
|
|
|
||||||
|
|
@ -1,45 +1,19 @@
|
||||||
use crate::executables::common::{EDGE_NODE_HOLDER, FORWARD_DESTINATION};
|
|
||||||
use crate::prudp::router::Router;
|
use crate::prudp::router::Router;
|
||||||
use crate::prudp::unsecure::Unsecure;
|
use crate::prudp::unsecure::Unsecure;
|
||||||
use log::error;
|
use log::error;
|
||||||
use rnex_core::common::setup;
|
use proxy_common::{ProxyStartupParam, RNEX_ACCESS_KEY};
|
||||||
use rnex_core::executables::common::{OWN_IP_PRIVATE, OWN_IP_PUBLIC, SERVER_PORT};
|
|
||||||
use rnex_core::prudp::virtual_port::VirtualPort;
|
use rnex_core::prudp::virtual_port::VirtualPort;
|
||||||
use rnex_core::reggie::EdgeNodeHolderConnectOption::Register;
|
|
||||||
use rnex_core::reggie::RemoteEdgeNodeHolder;
|
|
||||||
use rnex_core::reggie::UnitPacketRead;
|
use rnex_core::reggie::UnitPacketRead;
|
||||||
use rnex_core::reggie::UnitPacketWrite;
|
use rnex_core::reggie::UnitPacketWrite;
|
||||||
use rnex_core::rmc::protocols::{OnlyRemote, new_rmc_gateway_connection};
|
|
||||||
use rnex_core::rmc::structures::RmcSerialize;
|
use rnex_core::rmc::structures::RmcSerialize;
|
||||||
use rnex_core::rnex_proxy_common::ConnectionInitData;
|
use rnex_core::rnex_proxy_common::ConnectionInitData;
|
||||||
use rnex_core::util::SplittableBufferConnection;
|
|
||||||
use std::net::SocketAddrV4;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio::task;
|
use tokio::task;
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
use proxy_common::RNEX_ACCESS_KEY;
|
|
||||||
|
|
||||||
pub async fn start() {
|
pub async fn start(param: ProxyStartupParam) {
|
||||||
/*let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER)
|
let (router_secure, _) = Router::new(param.self_private)
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let conn: SplittableBufferConnection = conn.into();
|
|
||||||
|
|
||||||
conn.send(
|
|
||||||
Register(SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT))
|
|
||||||
.to_data()
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let conn = new_rmc_gateway_connection(conn, |r| {
|
|
||||||
Arc::new(OnlyRemote::<RemoteEdgeNodeHolder>::new(r))
|
|
||||||
});*/
|
|
||||||
|
|
||||||
let (router_secure, _) = Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT))
|
|
||||||
.await
|
.await
|
||||||
.expect("unable to start router");
|
.expect("unable to start router");
|
||||||
|
|
||||||
|
|
@ -48,8 +22,6 @@ pub async fn start() {
|
||||||
.await
|
.await
|
||||||
.expect("unable to add socket");
|
.expect("unable to add socket");
|
||||||
|
|
||||||
// let conn = socket_secure.connect(auth_sockaddr).await.unwrap();
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let Some(mut conn) = socket_secure.accept().await else {
|
let Some(mut conn) = socket_secure.accept().await else {
|
||||||
error!("server crashed");
|
error!("server crashed");
|
||||||
|
|
@ -57,7 +29,7 @@ pub async fn start() {
|
||||||
};
|
};
|
||||||
|
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
let mut stream = match TcpStream::connect(*FORWARD_DESTINATION).await {
|
let mut stream = match TcpStream::connect(param.forward_destination).await {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("unable to connect: {}", e);
|
error!("unable to connect: {}", e);
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,21 @@
|
||||||
use crate::executables::common::{EDGE_NODE_HOLDER, FORWARD_DESTINATION};
|
|
||||||
use crate::prudp::router::Router;
|
use crate::prudp::router::Router;
|
||||||
use crate::prudp::secure::Secure;
|
use crate::prudp::secure::Secure;
|
||||||
use log::error;
|
use log::error;
|
||||||
use rnex_core::common::setup;
|
use log::warn;
|
||||||
use rnex_core::executables::common::{
|
use proxy_common::{ProxyStartupParam, RNEX_ACCESS_KEY};
|
||||||
OWN_IP_PRIVATE, OWN_IP_PUBLIC, SECURE_SERVER_ACCOUNT, SERVER_PORT,
|
use rnex_core::executables::common::SECURE_SERVER_ACCOUNT;
|
||||||
};
|
|
||||||
use rnex_core::prudp::virtual_port::VirtualPort;
|
use rnex_core::prudp::virtual_port::VirtualPort;
|
||||||
use rnex_core::reggie::EdgeNodeHolderConnectOption::Register;
|
|
||||||
use rnex_core::reggie::RemoteEdgeNodeHolder;
|
|
||||||
use rnex_core::reggie::UnitPacketRead;
|
use rnex_core::reggie::UnitPacketRead;
|
||||||
use rnex_core::reggie::UnitPacketWrite;
|
use rnex_core::reggie::UnitPacketWrite;
|
||||||
use rnex_core::rmc::protocols::{OnlyRemote, new_rmc_gateway_connection};
|
|
||||||
use rnex_core::rmc::structures::RmcSerialize;
|
use rnex_core::rmc::structures::RmcSerialize;
|
||||||
use rnex_core::rnex_proxy_common::ConnectionInitData;
|
use rnex_core::rnex_proxy_common::ConnectionInitData;
|
||||||
use rnex_core::util::SplittableBufferConnection;
|
|
||||||
use std::net::SocketAddrV4;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio::task;
|
use tokio::task;
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
use proxy_common::RNEX_ACCESS_KEY;
|
|
||||||
|
|
||||||
pub async fn start() {
|
pub async fn start(param: ProxyStartupParam) {
|
||||||
let (router_secure, _) = Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT))
|
let (router_secure, _) = Router::new(param.self_private)
|
||||||
.await
|
.await
|
||||||
.expect("unable to start router");
|
.expect("unable to start router");
|
||||||
|
|
||||||
|
|
@ -36,8 +27,6 @@ pub async fn start() {
|
||||||
.await
|
.await
|
||||||
.expect("unable to add socket");
|
.expect("unable to add socket");
|
||||||
|
|
||||||
// let conn = socket_secure.connect(auth_sockaddr).await.unwrap();
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let Some(mut conn) = socket_secure.accept().await else {
|
let Some(mut conn) = socket_secure.accept().await else {
|
||||||
error!("server crashed");
|
error!("server crashed");
|
||||||
|
|
@ -45,7 +34,25 @@ pub async fn start() {
|
||||||
};
|
};
|
||||||
|
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
let mut stream = match TcpStream::connect(*FORWARD_DESTINATION).await {
|
let Ok(mut c) = rnex_core::grpc::account::Client::new().await else {
|
||||||
|
error!("failed to initialize gql client");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let v = match c.get_user_level(conn.user_id).await {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => {
|
||||||
|
error!("failed to get user level: {}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if v < 0 {
|
||||||
|
warn!("person with too low account level joined");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut stream = match TcpStream::connect(param.forward_destination).await {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("unable to connect: {}", e);
|
error!("unable to connect: {}", e);
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(feature = "prudpv1")]{
|
if #[cfg(feature = "prudpv1")]{
|
||||||
use proxy_common::{ProxyStartupParam, setup_edge_node_connection};
|
use proxy_common::ProxyStartupParam;
|
||||||
pub mod executables;
|
pub mod executables;
|
||||||
pub mod prudp;
|
pub mod prudp;
|
||||||
pub async fn start_secure(param: ProxyStartupParam) {
|
pub async fn start_secure(param: ProxyStartupParam) {
|
||||||
executables::proxy_secure::start().await;
|
executables::proxy_secure::start(param).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start_insecure(param: ProxyStartupParam) {
|
pub async fn start_insecure(param: ProxyStartupParam) {
|
||||||
executables::proxy_insecure::start().await;
|
executables::proxy_insecure::start(param).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ use rnex_core::prudp::socket_addr::PRUDPSockAddr;
|
||||||
use rnex_core::prudp::types_flags::TypesFlags;
|
use rnex_core::prudp::types_flags::TypesFlags;
|
||||||
use rnex_core::prudp::types_flags::flags::ACK;
|
use rnex_core::prudp::types_flags::flags::ACK;
|
||||||
use rnex_core::prudp::virtual_port::VirtualPort;
|
use rnex_core::prudp::virtual_port::VirtualPort;
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::Debug;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{Cursor, Read, Seek, Write};
|
use std::io::{Cursor, Read, Seek, Write};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
@ -447,7 +447,7 @@ mod test {
|
||||||
|
|
||||||
let bytes = &bytes[0x6..];
|
let bytes = &bytes[0x6..];
|
||||||
|
|
||||||
let header_data: [u8; 8] = bytes.try_into().unwrap();
|
let _: [u8; 8] = bytes.try_into().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,13 @@
|
||||||
use crate::prudp::packet::PRUDPV1Packet;
|
use crate::prudp::packet::PRUDPV1Packet;
|
||||||
use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance};
|
use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance};
|
||||||
use hmac::digest::consts::U32;
|
use hmac::digest::consts::U32;
|
||||||
use log::error;
|
|
||||||
use rc4::cipher::StreamCipherCoreWrapper;
|
use rc4::cipher::StreamCipherCoreWrapper;
|
||||||
use rc4::consts::U16;
|
|
||||||
use rc4::{KeyInit, Rc4, Rc4Core, StreamCipher};
|
use rc4::{KeyInit, Rc4, Rc4Core, StreamCipher};
|
||||||
use rnex_core::kerberos::{TicketInternalData, derive_key};
|
|
||||||
use rnex_core::nex::account::Account;
|
use rnex_core::nex::account::Account;
|
||||||
use rnex_core::prudp::encryption::EncryptionPair;
|
use rnex_core::prudp::encryption::EncryptionPair;
|
||||||
use rnex_core::prudp::ticket::read_secure_connection_data;
|
use rnex_core::prudp::ticket::read_secure_connection_data;
|
||||||
use rnex_core::rmc::structures::RmcSerialize;
|
use rnex_core::rmc::structures::RmcSerialize;
|
||||||
use std::io::Cursor;
|
|
||||||
use typenum::U5;
|
use typenum::U5;
|
||||||
use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions};
|
|
||||||
|
|
||||||
type Rc4U32 = StreamCipherCoreWrapper<Rc4Core<U32>>;
|
type Rc4U32 = StreamCipherCoreWrapper<Rc4Core<U32>>;
|
||||||
|
|
||||||
|
|
@ -52,6 +47,7 @@ pub struct SecureInstance {
|
||||||
session_key: [u8; 32],
|
session_key: [u8; 32],
|
||||||
streams: Vec<EncryptionPair<Rc4<U32>>>,
|
streams: Vec<EncryptionPair<Rc4<U32>>>,
|
||||||
self_signature: [u8; 16],
|
self_signature: [u8; 16],
|
||||||
|
#[allow(dead_code)]
|
||||||
remote_signature: [u8; 16],
|
remote_signature: [u8; 16],
|
||||||
pid: u32,
|
pid: u32,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ use std::io::Cursor;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
|
use tokio::spawn;
|
||||||
use v_byte_helpers::ReadExtensions;
|
use v_byte_helpers::ReadExtensions;
|
||||||
use v_byte_helpers::little_endian::read_u16;
|
use v_byte_helpers::little_endian::read_u16;
|
||||||
|
|
||||||
|
|
@ -68,6 +69,33 @@ impl<E: CryptoHandlerConnectionInstance> InternalConnection<E> {
|
||||||
prev_val
|
prev_val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn close_connection(&mut self) {
|
||||||
|
let mut packet = PRUDPV1Packet {
|
||||||
|
header: PRUDPV1Header {
|
||||||
|
sequence_id: self.next_server_count(),
|
||||||
|
substream_id: 0,
|
||||||
|
session_id: self.session_id,
|
||||||
|
types_and_flags: TypesFlags::default().types(DISCONNECT),
|
||||||
|
destination_port: self.common.socket_addr.virtual_port,
|
||||||
|
source_port: self.server_port,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
payload: Vec::new(),
|
||||||
|
options: vec![FragmentId(0)],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
// no need for encryption the, the payload is empty
|
||||||
|
|
||||||
|
packet.set_sizes();
|
||||||
|
|
||||||
|
self.crypto_handler_instance.sign_packet(&mut packet);
|
||||||
|
|
||||||
|
self.send_raw_packet(&packet).await;
|
||||||
|
|
||||||
|
self.delete_connection().await;
|
||||||
|
}
|
||||||
|
|
||||||
/// Sends a raw packet to a given client on the connection
|
/// Sends a raw packet to a given client on the connection
|
||||||
///
|
///
|
||||||
/// a raw packet is one which does not get processed any further(other than to send it
|
/// a raw packet is one which does not get processed any further(other than to send it
|
||||||
|
|
@ -103,7 +131,7 @@ pub struct ExternalConnection {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SendingConnection {
|
pub struct SendingConnection {
|
||||||
common: Arc<CommonConnection>,
|
common: Arc<CommonConnection>,
|
||||||
internal: Weak<Mutex<dyn AnyInternalConnection>>,
|
internal: Weak<dyn AnyInternalConnection>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CommonSocket {
|
pub struct CommonSocket {
|
||||||
|
|
@ -166,71 +194,67 @@ pub(super) trait AnyInternalSocket:
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub(super) trait AnyInternalConnection:
|
pub(super) trait AnyInternalConnection: Send + Sync + 'static {
|
||||||
Send + Sync + Deref<Target = CommonConnection> + 'static
|
async fn send_data_packet(&self, data: Vec<u8>);
|
||||||
{
|
|
||||||
async fn send_data_packet(&mut self, data: Vec<u8>);
|
|
||||||
|
|
||||||
async fn close_connection(&mut self);
|
async fn close_connection(&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<T: CryptoHandlerConnectionInstance> AnyInternalConnection for InternalConnection<T> {
|
impl<T: CryptoHandlerConnectionInstance> AnyInternalConnection for Mutex<InternalConnection<T>> {
|
||||||
async fn send_data_packet(&mut self, data: Vec<u8>) {
|
async fn send_data_packet(&self, data: Vec<u8>) {
|
||||||
let mut packet = PRUDPV1Packet {
|
let pieces = data.chunks(600);
|
||||||
header: PRUDPV1Header {
|
let max_piece = pieces.len() - 1;
|
||||||
sequence_id: self.next_server_count(),
|
let mut piece_num = 1;
|
||||||
substream_id: 0,
|
let mut locked = self.lock().await;
|
||||||
session_id: self.session_id,
|
let packets: Vec<_> = pieces
|
||||||
types_and_flags: TypesFlags::default().types(DATA).flags(RELIABLE | NEED_ACK),
|
.enumerate()
|
||||||
destination_port: self.common.socket_addr.virtual_port,
|
.map(|(i, piece)| {
|
||||||
source_port: self.server_port,
|
let mut packet = PRUDPV1Packet {
|
||||||
..Default::default()
|
header: PRUDPV1Header {
|
||||||
},
|
sequence_id: locked.next_server_count(),
|
||||||
payload: data,
|
substream_id: 0,
|
||||||
options: vec![FragmentId(0)],
|
session_id: locked.session_id,
|
||||||
..Default::default()
|
types_and_flags: TypesFlags::default()
|
||||||
};
|
.types(DATA)
|
||||||
|
.flags(RELIABLE | NEED_ACK),
|
||||||
|
destination_port: locked.common.socket_addr.virtual_port,
|
||||||
|
source_port: locked.server_port,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
payload: piece.to_owned(),
|
||||||
|
options: vec![FragmentId(if i == max_piece { 0 } else { piece_num })],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
self.crypto_handler_instance
|
locked
|
||||||
.encrypt_outgoing(0, &mut packet.payload[..]);
|
.crypto_handler_instance
|
||||||
|
.encrypt_outgoing(0, &mut packet.payload[..]);
|
||||||
|
|
||||||
packet.set_sizes();
|
packet.set_sizes();
|
||||||
|
|
||||||
self.crypto_handler_instance.sign_packet(&mut packet);
|
locked.crypto_handler_instance.sign_packet(&mut packet);
|
||||||
|
|
||||||
self.send_raw_packet(&packet).await;
|
piece_num += 1;
|
||||||
|
packet
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
drop(locked);
|
||||||
|
|
||||||
self.unacknowleged_packets.push((Instant::now(), packet));
|
for packet in packets {
|
||||||
|
let mut locked = self.lock().await;
|
||||||
|
locked.send_raw_packet(&packet).await;
|
||||||
|
|
||||||
|
locked.unacknowleged_packets.push((Instant::now(), packet));
|
||||||
|
drop(locked);
|
||||||
|
sleep(Duration::from_secs(16)).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn close_connection(&mut self) {
|
async fn close_connection(&self) {
|
||||||
// jon confirmed that this should be a safe way to dc a client
|
let mut locked = self.lock().await;
|
||||||
|
|
||||||
let mut packet = PRUDPV1Packet {
|
locked.close_connection().await;
|
||||||
header: PRUDPV1Header {
|
|
||||||
sequence_id: self.next_server_count(),
|
|
||||||
substream_id: 0,
|
|
||||||
session_id: self.session_id,
|
|
||||||
types_and_flags: TypesFlags::default().types(DISCONNECT),
|
|
||||||
destination_port: self.common.socket_addr.virtual_port,
|
|
||||||
source_port: self.server_port,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
payload: Vec::new(),
|
|
||||||
options: vec![FragmentId(0)],
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
// no need for encryption the, the payload is empty
|
|
||||||
|
|
||||||
packet.set_sizes();
|
|
||||||
|
|
||||||
self.crypto_handler_instance.sign_packet(&mut packet);
|
|
||||||
|
|
||||||
self.send_raw_packet(&packet).await;
|
|
||||||
|
|
||||||
self.delete_connection().await;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -394,7 +418,7 @@ impl<T: CryptoHandler> InternalSocket<T> {
|
||||||
|
|
||||||
let internal = Arc::new(Mutex::new(internal));
|
let internal = Arc::new(Mutex::new(internal));
|
||||||
|
|
||||||
let dyn_internal: Arc<Mutex<dyn AnyInternalConnection>> = internal.clone();
|
let dyn_internal: Arc<dyn AnyInternalConnection> = internal.clone();
|
||||||
|
|
||||||
let external = ExternalConnection {
|
let external = ExternalConnection {
|
||||||
sending: SendingConnection {
|
sending: SendingConnection {
|
||||||
|
|
@ -875,10 +899,9 @@ impl ExternalConnection {
|
||||||
impl SendingConnection {
|
impl SendingConnection {
|
||||||
pub async fn send(&self, data: Vec<u8>) -> Option<()> {
|
pub async fn send(&self, data: Vec<u8>) -> Option<()> {
|
||||||
let internal = self.internal.upgrade()?;
|
let internal = self.internal.upgrade()?;
|
||||||
|
spawn(async move {
|
||||||
let mut internal = internal.lock().await;
|
internal.send_data_packet(data).await;
|
||||||
|
});
|
||||||
internal.send_data_packet(data).await;
|
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -887,8 +910,6 @@ impl SendingConnection {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut internal = internal.lock().await;
|
|
||||||
|
|
||||||
internal.close_connection().await;
|
internal.close_connection().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::prudp::packet::PRUDPV1Packet;
|
use crate::prudp::packet::PRUDPV1Packet;
|
||||||
use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance};
|
use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance};
|
||||||
use once_cell::sync::Lazy;
|
use rc4::{KeyInit, Rc4, StreamCipher};
|
||||||
use rc4::{Key, KeyInit, Rc4, StreamCipher};
|
|
||||||
use rnex_core::prudp::encryption::{DEFAULT_KEY, EncryptionPair};
|
use rnex_core::prudp::encryption::{DEFAULT_KEY, EncryptionPair};
|
||||||
use typenum::U5;
|
use typenum::U5;
|
||||||
|
|
||||||
|
|
@ -11,6 +10,7 @@ pub struct UnsecureInstance {
|
||||||
key: &'static str,
|
key: &'static str,
|
||||||
streams: Vec<EncryptionPair<Rc4<U5>>>,
|
streams: Vec<EncryptionPair<Rc4<U5>>>,
|
||||||
self_signature: [u8; 16],
|
self_signature: [u8; 16],
|
||||||
|
#[allow(dead_code)]
|
||||||
remote_signature: [u8; 16],
|
remote_signature: [u8; 16],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "PostgreSQL",
|
|
||||||
"query": "SELECT owner, under_review FROM datastore.objects WHERE data_id = $1",
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"ordinal": 0,
|
|
||||||
"name": "owner",
|
|
||||||
"type_info": "Int4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 1,
|
|
||||||
"name": "under_review",
|
|
||||||
"type_info": "Bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Int8"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nullable": [
|
|
||||||
true,
|
|
||||||
false
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"hash": "164708b549c483a041d2e54065ed3ffbd9f8d5304f6aa6d785dbddbb1626c0e9"
|
|
||||||
}
|
|
||||||
|
|
@ -1,112 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "PostgreSQL",
|
|
||||||
"query": "SELECT data_id, owner, size, name, data_type, meta_binary,\n permission, permission_recipients, delete_permission, delete_permission_recipients,\n period, refer_data_id, flag, tags, creation_date, update_date\n FROM datastore.objects WHERE data_id = $1",
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"ordinal": 0,
|
|
||||||
"name": "data_id",
|
|
||||||
"type_info": "Int8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 1,
|
|
||||||
"name": "owner",
|
|
||||||
"type_info": "Int4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 2,
|
|
||||||
"name": "size",
|
|
||||||
"type_info": "Int4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 3,
|
|
||||||
"name": "name",
|
|
||||||
"type_info": "Text"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 4,
|
|
||||||
"name": "data_type",
|
|
||||||
"type_info": "Int4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 5,
|
|
||||||
"name": "meta_binary",
|
|
||||||
"type_info": "Bytea"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 6,
|
|
||||||
"name": "permission",
|
|
||||||
"type_info": "Int4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 7,
|
|
||||||
"name": "permission_recipients",
|
|
||||||
"type_info": "Int4Array"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 8,
|
|
||||||
"name": "delete_permission",
|
|
||||||
"type_info": "Int4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 9,
|
|
||||||
"name": "delete_permission_recipients",
|
|
||||||
"type_info": "Int4Array"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 10,
|
|
||||||
"name": "period",
|
|
||||||
"type_info": "Int4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 11,
|
|
||||||
"name": "refer_data_id",
|
|
||||||
"type_info": "Int8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 12,
|
|
||||||
"name": "flag",
|
|
||||||
"type_info": "Int4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 13,
|
|
||||||
"name": "tags",
|
|
||||||
"type_info": "TextArray"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 14,
|
|
||||||
"name": "creation_date",
|
|
||||||
"type_info": "Timestamp"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 15,
|
|
||||||
"name": "update_date",
|
|
||||||
"type_info": "Timestamp"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Int8"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"hash": "1c2be699b4bfc7e5e6d3a74d7badf67d1812b99e1ec952a044fc03e1a5c63703"
|
|
||||||
}
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "PostgreSQL",
|
|
||||||
"query": "\n INSERT INTO datastore.objects (\n owner, size, name, data_type, meta_binary,\n permission, permission_recipients,\n delete_permission, delete_permission_recipients,\n flag, period, refer_data_id, tags,\n persistence_slot_id, extra_data, creation_date, update_date\n ) VALUES (\n $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17\n ) RETURNING data_id\n ",
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"ordinal": 0,
|
|
||||||
"name": "data_id",
|
|
||||||
"type_info": "Int8"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Int4",
|
|
||||||
"Int4",
|
|
||||||
"Text",
|
|
||||||
"Int4",
|
|
||||||
"Bytea",
|
|
||||||
"Int4",
|
|
||||||
"Int4Array",
|
|
||||||
"Int4",
|
|
||||||
"Int4Array",
|
|
||||||
"Int4",
|
|
||||||
"Int4",
|
|
||||||
"Int8",
|
|
||||||
"TextArray",
|
|
||||||
"Int4",
|
|
||||||
"TextArray",
|
|
||||||
"Timestamp",
|
|
||||||
"Timestamp"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nullable": [
|
|
||||||
false
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"hash": "219fec3fc852f36de99e5f00ca7a1675439bb44c91158f8b8a696e326c45447c"
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "PostgreSQL",
|
|
||||||
"query": "\n INSERT INTO datastore.object_custom_rankings (data_id, application_id, value)\n VALUES ($1, $2, $3)\n ON CONFLICT (data_id, application_id)\n DO UPDATE SET value = datastore.object_custom_rankings.value + EXCLUDED.value\n ",
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Int8",
|
|
||||||
"Int8",
|
|
||||||
"Int8"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nullable": []
|
|
||||||
},
|
|
||||||
"hash": "29d4f5c07b36c3d3b6b54a86a1757f27247530878b7f82feeb65802d995a38c4"
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "PostgreSQL",
|
|
||||||
"query": "SELECT EXISTS(SELECT 1 FROM datastore.objects WHERE data_id = $1)",
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"ordinal": 0,
|
|
||||||
"name": "exists",
|
|
||||||
"type_info": "Bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Int8"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nullable": [
|
|
||||||
null
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"hash": "2ff34379bbc32276c3b78ef1283b8158ea907d36588e1e59f6cbe752d89361bb"
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "PostgreSQL",
|
|
||||||
"query": "\n SELECT data_id\n FROM datastore.objects\n WHERE owner = $1 AND data_type > 2 AND data_type < 50\n ",
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"ordinal": 0,
|
|
||||||
"name": "data_id",
|
|
||||||
"type_info": "Int8"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Int4"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nullable": [
|
|
||||||
false
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"hash": "37d449b81e2aa3abdbdaf38587ae1a6a6c5c38acb06d91c5b0924c3f0a5d2e92"
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "PostgreSQL",
|
|
||||||
"query": "\n SELECT buffer\n FROM datastore.buffer_queues\n WHERE data_id = $1 AND slot = $2\n ORDER BY creation_date ASC\n ",
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"ordinal": 0,
|
|
||||||
"name": "buffer",
|
|
||||||
"type_info": "Bytea"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Int8",
|
|
||||||
"Int4"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nullable": [
|
|
||||||
false
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"hash": "3d06238fddc72d1ba452602e1a8002e9186ce1dfc6c68b52d9d2a8a38f5c3a1f"
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "PostgreSQL",
|
|
||||||
"query": "\n SELECT\n rankings.data_id,\n rankings.value\n FROM datastore.object_custom_rankings rankings\n JOIN UNNEST($1::bigint[]) WITH ORDINALITY AS rows(data_id, ord)\n ON rankings.data_id = rows.data_id\n AND rankings.application_id = $2\n ORDER BY rows.ord\n ",
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"ordinal": 0,
|
|
||||||
"name": "data_id",
|
|
||||||
"type_info": "Int8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 1,
|
|
||||||
"name": "value",
|
|
||||||
"type_info": "Int8"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Int8Array",
|
|
||||||
"Int8"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
true
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"hash": "8605011b998a4608c739bf5ab388a7a9bf551126712c1d1089a4263453090e79"
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "PostgreSQL",
|
|
||||||
"query": "\n SELECT slot, total_value, count, initial_value\n FROM datastore.object_ratings\n WHERE data_id = $1\n ",
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"ordinal": 0,
|
|
||||||
"name": "slot",
|
|
||||||
"type_info": "Int2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 1,
|
|
||||||
"name": "total_value",
|
|
||||||
"type_info": "Int8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 2,
|
|
||||||
"name": "count",
|
|
||||||
"type_info": "Int4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 3,
|
|
||||||
"name": "initial_value",
|
|
||||||
"type_info": "Int8"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Int8"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
true
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"hash": "8706ac06d78ffaa2a45418be7ae71340561031d8e5c91f46c041f83e54c31a7d"
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "PostgreSQL",
|
|
||||||
"query": "\n SELECT under_review, access_password\n FROM datastore.objects\n WHERE data_id = $1 AND upload_completed = TRUE AND deleted = FALSE\n ",
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"ordinal": 0,
|
|
||||||
"name": "under_review",
|
|
||||||
"type_info": "Bool"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 1,
|
|
||||||
"name": "access_password",
|
|
||||||
"type_info": "Int8"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Int8"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"hash": "93be6b6b0ac5d85881e6e223a7d48f5eb4a3761dd71129ba6939cdd0d62569fb"
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "PostgreSQL",
|
|
||||||
"query": "UPDATE datastore.objects SET upload_completed = true WHERE data_id = $1",
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Int8"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nullable": []
|
|
||||||
},
|
|
||||||
"hash": "e28d8776cc49b55fe76cf33ac12fe18e500d243f1b55fd18e7d96d281605bcf9"
|
|
||||||
}
|
|
||||||
|
|
@ -1,125 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "PostgreSQL",
|
|
||||||
"query": "SELECT data_id, owner, size, name, data_type, meta_binary,\n permission, permission_recipients, delete_permission, delete_permission_recipients,\n period, refer_data_id, flag, tags, creation_date, update_date,\n access_password, under_review\n FROM datastore.objects\n WHERE owner = $1 AND persistence_slot_id = $2\n AND upload_completed = TRUE AND deleted = FALSE",
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"ordinal": 0,
|
|
||||||
"name": "data_id",
|
|
||||||
"type_info": "Int8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 1,
|
|
||||||
"name": "owner",
|
|
||||||
"type_info": "Int4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 2,
|
|
||||||
"name": "size",
|
|
||||||
"type_info": "Int4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 3,
|
|
||||||
"name": "name",
|
|
||||||
"type_info": "Text"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 4,
|
|
||||||
"name": "data_type",
|
|
||||||
"type_info": "Int4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 5,
|
|
||||||
"name": "meta_binary",
|
|
||||||
"type_info": "Bytea"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 6,
|
|
||||||
"name": "permission",
|
|
||||||
"type_info": "Int4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 7,
|
|
||||||
"name": "permission_recipients",
|
|
||||||
"type_info": "Int4Array"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 8,
|
|
||||||
"name": "delete_permission",
|
|
||||||
"type_info": "Int4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 9,
|
|
||||||
"name": "delete_permission_recipients",
|
|
||||||
"type_info": "Int4Array"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 10,
|
|
||||||
"name": "period",
|
|
||||||
"type_info": "Int4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 11,
|
|
||||||
"name": "refer_data_id",
|
|
||||||
"type_info": "Int8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 12,
|
|
||||||
"name": "flag",
|
|
||||||
"type_info": "Int4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 13,
|
|
||||||
"name": "tags",
|
|
||||||
"type_info": "TextArray"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 14,
|
|
||||||
"name": "creation_date",
|
|
||||||
"type_info": "Timestamp"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 15,
|
|
||||||
"name": "update_date",
|
|
||||||
"type_info": "Timestamp"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 16,
|
|
||||||
"name": "access_password",
|
|
||||||
"type_info": "Int8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 17,
|
|
||||||
"name": "under_review",
|
|
||||||
"type_info": "Bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Int4",
|
|
||||||
"Int4"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"hash": "efe4bf3602782a0d521274956e0fcecccf8f0f8dd20d890a76acf85265b2192c"
|
|
||||||
}
|
|
||||||
|
|
@ -34,6 +34,7 @@ aws-config = { version = "1.8.15", optional = true }
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
sha2 = "0.10.9"
|
sha2 = "0.10.9"
|
||||||
urlencoding = "2.1.3"
|
urlencoding = "2.1.3"
|
||||||
|
futures = "0.3.32"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
# criterion = "0.7.0"
|
# criterion = "0.7.0"
|
||||||
|
|
@ -41,12 +42,19 @@ urlencoding = "2.1.3"
|
||||||
[features]
|
[features]
|
||||||
rmc_struct_header = []
|
rmc_struct_header = []
|
||||||
guest_login = []
|
guest_login = []
|
||||||
friends = ["guest_login"]
|
friends = ["guest_login", "database-support"]
|
||||||
big_pid = []
|
big_pid = []
|
||||||
v3-8-15 = ["rmc_struct_header"]
|
v3-3-2 = []
|
||||||
|
third-notif-param = []
|
||||||
|
v3-4-0 = ["v3-3-2", "third-notif-param", "rmc_struct_header"]
|
||||||
|
v3-5-0 = ["v3-4-0"]
|
||||||
|
v3-8-15 = ["v3-5-0"]
|
||||||
|
v3-10-22 = ["v3-8-15"]
|
||||||
v4-3-11 = ["v3-8-15"]
|
v4-3-11 = ["v3-8-15"]
|
||||||
nx = ["big_pid"]
|
nx = ["big_pid"]
|
||||||
datastore = ["dep:sqlx", "v3-8-15", "dep:aws-sdk-s3", "dep:aws-config"]
|
splatoon = []
|
||||||
|
datastore = ["database-support", "v3-8-15", "dep:aws-sdk-s3", "dep:aws-config"]
|
||||||
|
database-support = ["dep:sqlx"]
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "rmc_serialization"
|
name = "rmc_serialization"
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,5 @@
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use rnex_core::common::setup;
|
use rnex_core::common::setup;
|
||||||
use rnex_core::executables::common::new_simple_backend;
|
|
||||||
use rnex_core::executables::friends_backend::start_friends_backend;
|
|
||||||
use rnex_core::nex::matchmake::MatchmakeManager;
|
|
||||||
use rnex_core::nex::remote_console::RemoteConsole;
|
|
||||||
use rnex_core::nex::user::User;
|
|
||||||
use rnex_core::rmc::protocols::{RemoteDisconnectable, RmcPureRemoteObject};
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::sync::atomic::AtomicU32;
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
|
@ -15,6 +7,7 @@ async fn main() {
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "friends")]{
|
if #[cfg(feature = "friends")]{
|
||||||
|
use rnex_core::executables::friends_backend::start_friends_backend;
|
||||||
start_friends_backend().await;
|
start_friends_backend().await;
|
||||||
} else if #[cfg(feature = "datastore")] {
|
} else if #[cfg(feature = "datastore")] {
|
||||||
use rnex_core::executables::common::DB_POOL;
|
use rnex_core::executables::common::DB_POOL;
|
||||||
|
|
|
||||||
|
|
@ -8,23 +8,21 @@ use std::io::Cursor;
|
||||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use std::sync::LazyLock;
|
|
||||||
use std::sync::OnceLock;
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "datastore")] {
|
if #[cfg(feature = "datastore")] {
|
||||||
use sqlx::postgres::PgPool;
|
use sqlx::postgres::PgPool;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
use crate::reggie::UnitPacketRead;
|
||||||
|
use cfg_if::cfg_if;
|
||||||
use log::error;
|
use log::error;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::string::ToString;
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
use crate::reggie::UnitPacketRead;
|
|
||||||
|
|
||||||
const IP_REQ_SERVICE_URL: &str = "https://ipinfo.io/ip";
|
const IP_REQ_SERVICE_URL: &str = "https://ipinfo.io/ip";
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "datastore")] {
|
if #[cfg(feature = "datastore")] {
|
||||||
|
use std::sync::{LazyLock, OnceLock};
|
||||||
pub static RNEX_DATASTORE_DATABASE_URL: LazyLock<String> = LazyLock::new(|| {
|
pub static RNEX_DATASTORE_DATABASE_URL: LazyLock<String> = LazyLock::new(|| {
|
||||||
std::env::var("RNEX_DATASTORE_DATABASE_URL")
|
std::env::var("RNEX_DATASTORE_DATABASE_URL")
|
||||||
.expect("RNEX_DATASTORE_DATABASE_URL must be set")
|
.expect("RNEX_DATASTORE_DATABASE_URL must be set")
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,11 @@ use log::error;
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
executables::common::{OWN_IP_PRIVATE, SERVER_PORT, new_simple_backend},
|
executables::common::{OWN_IP_PRIVATE, SERVER_PORT},
|
||||||
nex::friends_handler::{
|
nex::friends_handler::{FriendsGuest, FriendsManager, FriendsUser, RemoteFriendRemote},
|
||||||
FriendsGuest, FriendsManager, FriendsUser, RemoteFriendRemote, RemoteFriendsUser,
|
|
||||||
},
|
|
||||||
reggie::UnitPacketRead,
|
reggie::UnitPacketRead,
|
||||||
rmc::{
|
rmc::{
|
||||||
protocols::{
|
protocols::{RmcPureRemoteObject, new_rmc_gateway_connection},
|
||||||
RmcCallable, RmcPureRemoteObject, friends::RemoteFriends, new_rmc_gateway_connection,
|
|
||||||
},
|
|
||||||
structures::RmcSerialize,
|
structures::RmcSerialize,
|
||||||
},
|
},
|
||||||
rnex_proxy_common::ConnectionInitData,
|
rnex_proxy_common::ConnectionInitData,
|
||||||
|
|
@ -65,8 +61,8 @@ pub async fn start_friends_backend() {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
new_rmc_gateway_connection(stream.into(), move |r| {
|
new_rmc_gateway_connection(stream.into(), move |_| {
|
||||||
Arc::new_cyclic(move |this| FriendsGuest {
|
Arc::new_cyclic(move |_| FriendsGuest {
|
||||||
fm,
|
fm,
|
||||||
addr: c.prudpsock_addr,
|
addr: c.prudpsock_addr,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,10 @@
|
||||||
|
use cfg_if::cfg_if;
|
||||||
|
|
||||||
pub mod common;
|
pub mod common;
|
||||||
pub mod friends_backend;
|
cfg_if! {
|
||||||
pub mod regular_backend;
|
if #[cfg(feature = "friends")]{
|
||||||
|
pub mod friends_backend;
|
||||||
|
} else {
|
||||||
|
pub mod regular_backend;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ pub async fn start_regular_backend() {
|
||||||
//gid_counter: AtomicU32::new(1),
|
//gid_counter: AtomicU32::new(1),
|
||||||
sessions: Default::default(),
|
sessions: Default::default(),
|
||||||
users: Default::default(),
|
users: Default::default(),
|
||||||
|
users_by_pid: Default::default(),
|
||||||
rv_cid_counter: AtomicU32::new(1),
|
rv_cid_counter: AtomicU32::new(1),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,41 @@ impl Client {
|
||||||
Ok(val.as_bytes().try_into().map_err(|_| SomethingHappened)?)
|
Ok(val.as_bytes().try_into().map_err(|_| SomethingHappened)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_user_level(&mut self, pid: PID) -> Result<i32> {
|
||||||
|
let req = self
|
||||||
|
.do_request(object! {
|
||||||
|
"query": r"query($pid: Int!){
|
||||||
|
userByPid(pid: $pid){
|
||||||
|
accountLevel
|
||||||
|
}
|
||||||
|
}",
|
||||||
|
"variables": {
|
||||||
|
"pid": pid
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let Some(val) = req
|
||||||
|
.entries()
|
||||||
|
.find(|v| v.0 == "data")
|
||||||
|
.ok_or(SomethingHappened)?
|
||||||
|
.1
|
||||||
|
.entries()
|
||||||
|
.find(|v| v.0 == "userByPid")
|
||||||
|
.ok_or(SomethingHappened)?
|
||||||
|
.1
|
||||||
|
.entries()
|
||||||
|
.find(|v| v.0 == "accountLevel")
|
||||||
|
.ok_or(SomethingHappened)?
|
||||||
|
.1
|
||||||
|
.as_i32()
|
||||||
|
else {
|
||||||
|
return Err(SomethingHappened);
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(val)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_pid_from_token(&mut self, token: String) -> Result<PID> {
|
pub async fn get_pid_from_token(&mut self, token: String) -> Result<PID> {
|
||||||
let req = self
|
let req = self
|
||||||
.do_request(object! {
|
.do_request(object! {
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,13 @@ use rnex_core::PID;
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "friends")]{
|
if #[cfg(feature = "friends")]{
|
||||||
pub type SESSION_KEY_LENGTH_TY = U16;
|
pub type SessionLengthTy = U16;
|
||||||
} else {
|
} else {
|
||||||
use rc4::consts::U32;
|
use rc4::consts::U32;
|
||||||
pub type SESSION_KEY_LENGTH_TY = U32;
|
pub type SessionLengthTy = U32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub const SESSION_KEY_LENGTH: usize = SESSION_KEY_LENGTH_TY::USIZE;
|
pub const SESSION_KEY_LENGTH: usize = SessionLengthTy::USIZE;
|
||||||
|
|
||||||
type Md5Hmac = Hmac<md5::Md5>;
|
type Md5Hmac = Hmac<md5::Md5>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,127 +0,0 @@
|
||||||
#![allow(dead_code)]
|
|
||||||
#![allow(async_fn_in_trait)]
|
|
||||||
//#![warn(missing_docs)]
|
|
||||||
|
|
||||||
//! # Splatoon RNEX server
|
|
||||||
//!
|
|
||||||
//! This server still includes the code for rnex itself as this is the first rnex server and thus
|
|
||||||
//! also the first and only current usage of rnex, expect this and rnex to be split into seperate
|
|
||||||
//! repos soon.
|
|
||||||
|
|
||||||
extern crate self as rust_nex;
|
|
||||||
|
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
use std::hint::black_box;
|
|
||||||
|
|
||||||
mod prudp;
|
|
||||||
pub mod rmc;
|
|
||||||
//mod protocols;
|
|
||||||
|
|
||||||
mod grpc;
|
|
||||||
mod kerberos;
|
|
||||||
mod nex;
|
|
||||||
mod result;
|
|
||||||
mod versions;
|
|
||||||
pub mod reggie;
|
|
||||||
pub mod util;
|
|
||||||
pub mod common;
|
|
||||||
|
|
||||||
pub mod config{
|
|
||||||
pub const FEATURE_HAS_STRUCT_HEADER: bool = cfg!(feature = "rmc_struct_header");
|
|
||||||
}
|
|
||||||
|
|
||||||
use std::io::Cursor;
|
|
||||||
use std::ops::Deref;
|
|
||||||
use rnex_core::kerberos::KerberosDateTime;
|
|
||||||
use rnex_core::rmc::structures::matchmake::{AutoMatchmakeParam, Gathering, MatchmakeParam, MatchmakeSession, MatchmakeSessionSearchCriteria};
|
|
||||||
use rnex_core::rmc::structures::RmcSerialize;
|
|
||||||
use rnex_core::rmc::structures::variant::Variant;
|
|
||||||
|
|
||||||
static DUMMY: Lazy<AutoMatchmakeParam> = Lazy::new(|| AutoMatchmakeParam{
|
|
||||||
additional_participants: vec![1,2,3,4],
|
|
||||||
auto_matchmake_option: 10,
|
|
||||||
gid_for_participation_check: 9,
|
|
||||||
join_message: "hi".to_string(),
|
|
||||||
participation_count: 32,
|
|
||||||
target_gids: vec![45,2,51,1,1,1,1],
|
|
||||||
search_criteria: vec![MatchmakeSessionSearchCriteria{
|
|
||||||
attribs: vec!["hi".to_string(), "ig".to_string(), "gotta put data here".to_string()],
|
|
||||||
exclude_locked: true,
|
|
||||||
exclude_non_host_pid: false,
|
|
||||||
exclude_system_password_set: true,
|
|
||||||
exclude_user_password_set: false,
|
|
||||||
game_mode: "some gamemode".to_string(),
|
|
||||||
matchmake_param: MatchmakeParam{
|
|
||||||
params: vec![
|
|
||||||
("SR".to_string(), Variant::Bool(true)),
|
|
||||||
("SR2".to_string(), Variant::Double(1.0)),
|
|
||||||
("SR3".to_string(), Variant::SInt64(42)),
|
|
||||||
("SR4".to_string(), Variant::String("test".to_string()))
|
|
||||||
]
|
|
||||||
},
|
|
||||||
matchmake_system_type: "some type".to_string(),
|
|
||||||
maximum_participants: "???".to_string(),
|
|
||||||
minimum_participants: "-99".to_string(),
|
|
||||||
refer_gid: 123,
|
|
||||||
selection_method: 9999999,
|
|
||||||
vacant_only: true,
|
|
||||||
vacant_participants: 1000
|
|
||||||
}],
|
|
||||||
matchmake_session: MatchmakeSession{
|
|
||||||
refer_gid: 10,
|
|
||||||
matchmake_system_type: 139,
|
|
||||||
matchmake_param: MatchmakeParam{
|
|
||||||
params: vec![
|
|
||||||
("QSR".to_string(), Variant::Bool(false)),
|
|
||||||
("SRQ2".to_string(), Variant::Double(1.1)),
|
|
||||||
("SQR3".to_string(), Variant::SInt64(422)),
|
|
||||||
("SDR4".to_string(), Variant::String("tetst".to_string()))
|
|
||||||
]
|
|
||||||
},
|
|
||||||
participation_count: 99,
|
|
||||||
application_buffer: vec![1,2,3,4,5,6,7,8,9],
|
|
||||||
attributes: vec![10,20,99,100000],
|
|
||||||
datetime: KerberosDateTime::now(),
|
|
||||||
gamemode: 111,
|
|
||||||
open_participation: false,
|
|
||||||
option0: 100,
|
|
||||||
progress_score: 1,
|
|
||||||
system_password_enabled: false,
|
|
||||||
user_password: "aaa".to_string(),
|
|
||||||
session_key: vec![91,123,5,2,1,2,4,124,4],
|
|
||||||
user_password_enabled: false,
|
|
||||||
gathering: Gathering{
|
|
||||||
minimum_participants: 1,
|
|
||||||
maximum_participants: 12,
|
|
||||||
description: "aaargh".to_string(),
|
|
||||||
flags: 100,
|
|
||||||
host_pid: 999999919,
|
|
||||||
owner_pid: 138830,
|
|
||||||
participant_policy: 1,
|
|
||||||
policy_argument: 99837,
|
|
||||||
self_gid: 129,
|
|
||||||
state: 1389488
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
static DUMMY_SER: Lazy<Vec<u8>> = Lazy::new(|| serialize_to_vec(DUMMY.deref()));
|
|
||||||
|
|
||||||
fn serialize_to_vec(r: &impl RmcSerialize) -> Vec<u8>{
|
|
||||||
let vec = r.to_data();
|
|
||||||
|
|
||||||
vec.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_struct<T: RmcSerialize>(r: &[u8]) -> T{
|
|
||||||
T::deserialize(&mut Cursor::new(r)).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main(){
|
|
||||||
for _ in 0..10000000 {
|
|
||||||
let v = serialize_to_vec(black_box(DUMMY.deref()));
|
|
||||||
let u = read_struct::<AutoMatchmakeParam>(black_box(DUMMY_SER.deref().as_slice()));
|
|
||||||
black_box(v);
|
|
||||||
black_box(u);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -129,7 +129,7 @@ impl AuthHandler {
|
||||||
};
|
};
|
||||||
|
|
||||||
let Ok(passwd) = client.get_nex_password(pid).await else {
|
let Ok(passwd) = client.get_nex_password(pid).await else {
|
||||||
warn!("unable to get nex password");
|
warn!("unable to get nex password for pid: {}:", pid);
|
||||||
return Err(ErrorCode::Core_Exception);
|
return Err(ErrorCode::Core_Exception);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -337,82 +337,3 @@ impl Auth for AuthHandler {
|
||||||
Err(ErrorCode::Core_Exception)
|
Err(ErrorCode::Core_Exception)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod test {
|
|
||||||
use std::io::Cursor;
|
|
||||||
|
|
||||||
use rc4::{KeyInit, Rc4, StreamCipher};
|
|
||||||
use rnex_core::PID;
|
|
||||||
use rnex_core::kerberos::KerberosDateTime;
|
|
||||||
use rnex_core::rmc::structures::connection_data::ConnectionData;
|
|
||||||
use rnex_core::rmc::{
|
|
||||||
response::ErrorCode,
|
|
||||||
structures::{RmcSerialize, qresult::QResult},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::kerberos::{self, derive_key};
|
|
||||||
use crate::rmc;
|
|
||||||
use crate::rmc::message::RMCMessage;
|
|
||||||
use crate::rmc::response::{RMCResponse, RMCResponseResult};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test() {
|
|
||||||
return;
|
|
||||||
let packet = [
|
|
||||||
26, 1, 0, 0, 10, 1, 30, 0, 0, 0, 1, 128, 0, 0, 1, 0, 1, 0, 86, 4, 0, 0, 116, 0, 0, 0,
|
|
||||||
144, 209, 130, 175, 45, 215, 95, 55, 226, 192, 51, 54, 201, 84, 118, 150, 159, 164, 32,
|
|
||||||
103, 134, 252, 199, 168, 178, 5, 6, 208, 206, 241, 94, 23, 136, 37, 109, 247, 156, 252,
|
|
||||||
189, 233, 142, 115, 206, 72, 180, 57, 106, 223, 37, 59, 144, 208, 250, 197, 51, 202,
|
|
||||||
185, 156, 51, 159, 219, 117, 250, 103, 184, 1, 103, 108, 15, 14, 174, 160, 192, 146,
|
|
||||||
135, 10, 55, 125, 68, 181, 88, 127, 183, 34, 4, 213, 19, 146, 81, 56, 248, 213, 241,
|
|
||||||
168, 205, 253, 29, 10, 123, 198, 177, 157, 247, 209, 113, 167, 231, 42, 214, 15, 12,
|
|
||||||
200, 192, 230, 125, 227, 74, 0, 112, 114, 117, 100, 112, 115, 58, 47, 80, 73, 68, 61,
|
|
||||||
50, 59, 115, 105, 100, 61, 49, 59, 115, 116, 114, 101, 97, 109, 61, 49, 48, 59, 116,
|
|
||||||
121, 112, 101, 61, 50, 59, 97, 100, 100, 114, 101, 115, 115, 61, 57, 49, 46, 57, 56,
|
|
||||||
46, 49, 50, 56, 46, 56, 54, 59, 112, 111, 114, 116, 61, 54, 48, 48, 49, 59, 67, 73, 68,
|
|
||||||
61, 49, 0, 0, 0, 0, 0, 1, 0, 0, 162, 243, 240, 168, 31, 0, 0, 0, 51, 0, 98, 114, 97,
|
|
||||||
110, 99, 104, 58, 111, 114, 105, 103, 105, 110, 47, 112, 114, 111, 106, 101, 99, 116,
|
|
||||||
47, 119, 117, 112, 45, 97, 103, 109, 106, 32, 98, 117, 105, 108, 100, 58, 51, 95, 56,
|
|
||||||
95, 49, 53, 95, 50, 48, 48, 52, 95, 48, 0,
|
|
||||||
];
|
|
||||||
let rmc_packet = RMCResponse::new(&mut Cursor::new(&packet)).unwrap();
|
|
||||||
println!("{:?}", rmc_packet);
|
|
||||||
|
|
||||||
let RMCResponseResult::Success {
|
|
||||||
call_id,
|
|
||||||
method_id,
|
|
||||||
data,
|
|
||||||
} = rmc_packet.response_result
|
|
||||||
else {
|
|
||||||
panic!();
|
|
||||||
};
|
|
||||||
|
|
||||||
println!("{}", hex::encode(&data));
|
|
||||||
|
|
||||||
let mut data =
|
|
||||||
<(QResult, PID, Vec<u8>, ConnectionData, String) as RmcSerialize>::deserialize(
|
|
||||||
&mut Cursor::new(&data[..]),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
println!("{:?}", data);
|
|
||||||
|
|
||||||
let key = derive_key(1110, "AAAAAAAAAAAAAAAA".as_bytes());
|
|
||||||
|
|
||||||
let mut rc4 = Rc4::new((&key).into());
|
|
||||||
|
|
||||||
rc4.apply_keystream(&mut data.2);
|
|
||||||
println!("raw tick: {:?}", data.2);
|
|
||||||
|
|
||||||
let tick: &kerberos::Ticket =
|
|
||||||
bytemuck::from_bytes(&data.2[..size_of::<kerberos::Ticket>()]);
|
|
||||||
|
|
||||||
let remainder = &data.2[size_of::<kerberos::Ticket>()..];
|
|
||||||
|
|
||||||
println!("tick: {:?}", tick);
|
|
||||||
let data = <Vec<u8> as RmcSerialize>::deserialize(&mut Cursor::new(remainder)).unwrap();
|
|
||||||
println!("inner ticket raw: {:?}", data);
|
|
||||||
|
|
||||||
println!("{:?}", data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -139,6 +139,9 @@ impl Friends for FriendsUser {
|
||||||
let Ok(any_self_fr_info) = Any::new(&self_fr_info) else {
|
let Ok(any_self_fr_info) = Any::new(&self_fr_info) else {
|
||||||
return Err(ErrorCode::RendezVous_ControlScriptFailure);
|
return Err(ErrorCode::RendezVous_ControlScriptFailure);
|
||||||
};
|
};
|
||||||
|
let Ok(any_self_presence) = Any::new(&self_fr_info.presence) else {
|
||||||
|
return Err(ErrorCode::RendezVous_ControlScriptFailure);
|
||||||
|
};
|
||||||
drop(data);
|
drop(data);
|
||||||
|
|
||||||
let mut fr_list = vec![FriendInfo {
|
let mut fr_list = vec![FriendInfo {
|
||||||
|
|
@ -197,6 +200,9 @@ impl Friends for FriendsUser {
|
||||||
|
|
||||||
println!("acquiring user and current friends locks");
|
println!("acquiring user and current friends locks");
|
||||||
let users = self.fm.users.read().await;
|
let users = self.fm.users.read().await;
|
||||||
|
if users.iter().filter(|u| u.upgrade().is_some()).count() >= 100 {
|
||||||
|
return Err(ErrorCode::RendezVous_ConnectionFailure);
|
||||||
|
}
|
||||||
println!("started summing users");
|
println!("started summing users");
|
||||||
for u in users.deref().iter().filter_map(|u| u.upgrade()) {
|
for u in users.deref().iter().filter_map(|u| u.upgrade()) {
|
||||||
let data = u.data.read().await;
|
let data = u.data.read().await;
|
||||||
|
|
@ -227,6 +233,18 @@ impl Friends for FriendsUser {
|
||||||
.await;
|
.await;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
let data = any_self_presence.clone();
|
||||||
|
let u = u.clone();
|
||||||
|
let sender = self.pid;
|
||||||
|
spawn(async move {
|
||||||
|
u.remote
|
||||||
|
.process_nintendo_notification_event_2(NintendoNotificationEvent {
|
||||||
|
event_type: 24,
|
||||||
|
sender,
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
});
|
||||||
drop(fr);
|
drop(fr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -263,18 +281,22 @@ impl Friends for FriendsUser {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update_presence(&self, presence: NintendoPresenceV2) -> Result<(), ErrorCode> {
|
async fn update_presence(&self, presence: NintendoPresenceV2) -> Result<(), ErrorCode> {
|
||||||
|
info!("user updated presence: {:?}", presence);
|
||||||
let mut data = self.data.write().await;
|
let mut data = self.data.write().await;
|
||||||
let Some(inner_data) = data.as_mut() else {
|
let Some(inner_data) = data.as_mut() else {
|
||||||
|
log::error!("unable to get presence data");
|
||||||
return Err(ErrorCode::RendezVous_PermissionDenied);
|
return Err(ErrorCode::RendezVous_PermissionDenied);
|
||||||
};
|
};
|
||||||
inner_data.presence = presence;
|
inner_data.presence = presence;
|
||||||
let Ok(any_self_fr_info) = Any::new(&inner_data.presence) else {
|
let Ok(any_self_fr_info) = Any::new(&inner_data.presence) else {
|
||||||
|
log::error!("unable to create presence any data holder");
|
||||||
return Err(ErrorCode::RendezVous_ControlScriptFailure);
|
return Err(ErrorCode::RendezVous_ControlScriptFailure);
|
||||||
};
|
};
|
||||||
drop(data);
|
drop(data);
|
||||||
|
|
||||||
let users = self.fm.users.read().await;
|
let users = self.fm.users.read().await;
|
||||||
for u in users.deref().iter().filter_map(|u| u.upgrade()) {
|
for u in users.deref().iter().filter_map(|u| u.upgrade()) {
|
||||||
|
info!("sending presence update");
|
||||||
u.remote
|
u.remote
|
||||||
.process_nintendo_notification_event_2(NintendoNotificationEvent {
|
.process_nintendo_notification_event_2(NintendoNotificationEvent {
|
||||||
event_type: 24,
|
event_type: 24,
|
||||||
|
|
@ -290,7 +312,7 @@ impl Friends for FriendsUser {
|
||||||
|
|
||||||
async fn delete_persistent_notification(
|
async fn delete_persistent_notification(
|
||||||
&self,
|
&self,
|
||||||
notifs: Vec<PersistentNotification>,
|
_notifs: Vec<PersistentNotification>,
|
||||||
) -> Result<(), ErrorCode> {
|
) -> Result<(), ErrorCode> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -298,6 +320,26 @@ impl Friends for FriendsUser {
|
||||||
async fn check_setting_status(&self) -> Result<u8, ErrorCode> {
|
async fn check_setting_status(&self) -> Result<u8, ErrorCode> {
|
||||||
Ok(0xFF)
|
Ok(0xFF)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn update_preference(&self, preference: PrincipalPreference) -> Result<(),ErrorCode> {
|
||||||
|
info!("user updated preference: {:?}", preference);
|
||||||
|
let any_presence: Any = Any::new(&preference).expect("out of memory");
|
||||||
|
|
||||||
|
let users = self.fm.users.read().await;
|
||||||
|
for u in users.deref().iter().filter_map(|u| u.upgrade()) {
|
||||||
|
info!("sending preference update");
|
||||||
|
u.remote
|
||||||
|
.process_nintendo_notification_event_2(NintendoNotificationEvent {
|
||||||
|
event_type: 23,
|
||||||
|
sender: self.pid,
|
||||||
|
data: any_presence.clone(),
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
drop(users);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type HMacMd5 = hmac::Hmac<md5::Md5>;
|
type HMacMd5 = hmac::Hmac<md5::Md5>;
|
||||||
|
|
@ -308,6 +350,10 @@ impl Secure for FriendsUser {
|
||||||
station_urls: Vec<StationUrl>,
|
station_urls: Vec<StationUrl>,
|
||||||
) -> Result<(QResult, u32, StationUrl), ErrorCode> {
|
) -> Result<(QResult, u32, StationUrl), ErrorCode> {
|
||||||
let cid = self.fm.next_cid();
|
let cid = self.fm.next_cid();
|
||||||
|
let users = self.fm.users.read().await;
|
||||||
|
if users.iter().filter(|u| u.upgrade().is_some()).count() >= 100 {
|
||||||
|
return Err(ErrorCode::RendezVous_ConnectionFailure);
|
||||||
|
}
|
||||||
Ok((
|
Ok((
|
||||||
QResult::success(ErrorCode::Core_Unknown),
|
QResult::success(ErrorCode::Core_Unknown),
|
||||||
cid,
|
cid,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
use crate::nex::user::User;
|
|
||||||
use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification};
|
|
||||||
use log::info;
|
use log::info;
|
||||||
use rand::random;
|
use rand::random;
|
||||||
use rnex_core::PID;
|
use rnex_core::PID;
|
||||||
use rnex_core::kerberos::KerberosDateTime;
|
use rnex_core::kerberos::KerberosDateTime;
|
||||||
|
use rnex_core::nex::user::User;
|
||||||
use rnex_core::rmc::protocols::notifications::notification_types::{
|
use rnex_core::rmc::protocols::notifications::notification_types::{
|
||||||
HOST_CHANGED, OWNERSHIP_CHANGED,
|
HOST_CHANGED, OWNERSHIP_CHANGED,
|
||||||
};
|
};
|
||||||
|
use rnex_core::rmc::protocols::notifications::{NotificationEvent, RemoteNotification};
|
||||||
use rnex_core::rmc::response::ErrorCode;
|
use rnex_core::rmc::response::ErrorCode;
|
||||||
use rnex_core::rmc::response::ErrorCode::{Core_InvalidArgument, RendezVous_SessionVoid};
|
use rnex_core::rmc::response::ErrorCode::{Core_InvalidArgument, RendezVous_SessionVoid};
|
||||||
use rnex_core::rmc::structures::matchmake::gathering_flags::PERSISTENT_GATHERING;
|
use rnex_core::rmc::structures::matchmake::gathering_flags::PERSISTENT_GATHERING;
|
||||||
|
|
@ -28,6 +28,7 @@ pub struct MatchmakeManager {
|
||||||
pub sessions: RwLock<HashMap<u32, Arc<Mutex<ExtendedMatchmakeSession>>>>,
|
pub sessions: RwLock<HashMap<u32, Arc<Mutex<ExtendedMatchmakeSession>>>>,
|
||||||
pub rv_cid_counter: AtomicU32,
|
pub rv_cid_counter: AtomicU32,
|
||||||
pub users: RwLock<HashMap<u32, Weak<User>>>,
|
pub users: RwLock<HashMap<u32, Weak<User>>>,
|
||||||
|
pub users_by_pid: RwLock<HashMap<u32, Weak<User>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MatchmakeManager {
|
impl MatchmakeManager {
|
||||||
|
|
@ -114,9 +115,16 @@ fn read_bounds_string<T: FromStr>(str: &str) -> Option<(T, T)> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_bounds_str<T: FromStr + PartialOrd>(compare: T, str: &str) -> Option<bool> {
|
fn check_bounds_str<T: FromStr + PartialOrd>(compare: T, str: &str) -> Option<bool> {
|
||||||
let bounds: (T, T) = read_bounds_string(str)?;
|
if let Some(bounds) = read_bounds_string::<T>(str) {
|
||||||
|
return Some(bounds.0 <= compare && compare <= bounds.1);
|
||||||
Some(bounds.0 <= compare && compare <= bounds.1)
|
}
|
||||||
|
if let Ok(val) = T::from_str(str) {
|
||||||
|
return Some(val == compare);
|
||||||
|
}
|
||||||
|
if str.is_empty() {
|
||||||
|
return Some(true);
|
||||||
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn broadcast_notification<T: AsRef<User>>(
|
pub async fn broadcast_notification<T: AsRef<User>>(
|
||||||
|
|
@ -155,28 +163,47 @@ impl ExtendedMatchmakeSession {
|
||||||
return Default::default();
|
return Default::default();
|
||||||
};
|
};
|
||||||
|
|
||||||
let mm_session = MatchmakeSession {
|
cfg_if::cfg_if! {
|
||||||
gathering: Gathering {
|
if #[cfg(feature = "v3-5-0")]{
|
||||||
self_gid: gid,
|
let mm_session = MatchmakeSession {
|
||||||
owner_pid: host.pid,
|
gathering: Gathering {
|
||||||
host_pid: host.pid,
|
self_gid: gid,
|
||||||
..session.gathering.clone()
|
owner_pid: host.pid,
|
||||||
},
|
host_pid: host.pid,
|
||||||
datetime: KerberosDateTime::now(),
|
..session.gathering.clone()
|
||||||
session_key: (0..32).map(|_| random()).collect(),
|
},
|
||||||
matchmake_param: MatchmakeParam {
|
datetime: KerberosDateTime::now(),
|
||||||
params: vec![
|
session_key: (0..32).map(|_| random()).collect(),
|
||||||
("@SR".to_owned(), Variant::Bool(true)),
|
matchmake_param: MatchmakeParam {
|
||||||
("@GIR".to_owned(), Variant::SInt64(3)),
|
params: vec![
|
||||||
],
|
("@SR".to_owned(), Variant::Bool(true)),
|
||||||
},
|
("@GIR".to_owned(), Variant::SInt64(3)),
|
||||||
system_password_enabled: false,
|
],
|
||||||
..session
|
},
|
||||||
};
|
system_password_enabled: false,
|
||||||
|
..session
|
||||||
|
};
|
||||||
|
|
||||||
Self {
|
return Self {
|
||||||
session: mm_session,
|
session: mm_session,
|
||||||
connected_players: Default::default(),
|
connected_players: Default::default(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mm_session = MatchmakeSession {
|
||||||
|
gathering: Gathering {
|
||||||
|
self_gid: gid,
|
||||||
|
owner_pid: host.pid,
|
||||||
|
host_pid: host.pid,
|
||||||
|
..session.gathering.clone()
|
||||||
|
},
|
||||||
|
session_key: (0..32).map(|_| random()).collect(),
|
||||||
|
..session
|
||||||
|
};
|
||||||
|
return Self {
|
||||||
|
session: mm_session,
|
||||||
|
connected_players: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,6 +239,7 @@ impl ExtendedMatchmakeSession {
|
||||||
param_1: self.session.gathering.self_gid as PID,
|
param_1: self.session.gathering.self_gid as PID,
|
||||||
param_2: other_pid,
|
param_2: other_pid,
|
||||||
str_param: "".into(),
|
str_param: "".into(),
|
||||||
|
#[cfg(feature = "third-notif-param")]
|
||||||
param_3: 0,
|
param_3: 0,
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
@ -244,6 +272,7 @@ impl ExtendedMatchmakeSession {
|
||||||
param_1: self.session.gathering.self_gid as PID,
|
param_1: self.session.gathering.self_gid as PID,
|
||||||
param_2: *pid,
|
param_2: *pid,
|
||||||
str_param: join_msg.clone(),
|
str_param: join_msg.clone(),
|
||||||
|
#[cfg(feature = "third-notif-param")]
|
||||||
param_3: self.connected_players.len() as _,
|
param_3: self.connected_players.len() as _,
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
@ -266,6 +295,7 @@ impl ExtendedMatchmakeSession {
|
||||||
param_1: self.session.gathering.self_gid as PID,
|
param_1: self.session.gathering.self_gid as PID,
|
||||||
param_2: new_conn_pid,
|
param_2: new_conn_pid,
|
||||||
str_param: join_msg.clone(),
|
str_param: join_msg.clone(),
|
||||||
|
#[cfg(feature = "third-notif-param")]
|
||||||
param_3: self.connected_players.len() as _,
|
param_3: self.connected_players.len() as _,
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
@ -318,15 +348,19 @@ impl ExtendedMatchmakeSession {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if search_criteria.exclude_system_password_set {
|
cfg_if::cfg_if! {
|
||||||
if self.session.system_password_enabled {
|
if #[cfg(feature = "v3-5-0")]{
|
||||||
return Ok(false);
|
if search_criteria.exclude_system_password_set {
|
||||||
}
|
if self.session.system_password_enabled {
|
||||||
}
|
return Ok(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if search_criteria.exclude_user_password_set {
|
if search_criteria.exclude_user_password_set {
|
||||||
if self.session.user_password_enabled {
|
if self.session.user_password_enabled {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -366,32 +400,32 @@ impl ExtendedMatchmakeSession {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if search_criteria
|
#[cfg(feature = "splatoon")]
|
||||||
.attribs
|
|
||||||
.get(0)
|
|
||||||
.map(|str| str.parse().ok())
|
|
||||||
.flatten()
|
|
||||||
!= self.session.attributes.get(0).map(|v| *v)
|
|
||||||
{
|
{
|
||||||
return Ok(false);
|
if search_criteria.attribs.get(0).is_some_and(|s| {
|
||||||
}
|
self.session
|
||||||
if search_criteria
|
.attributes
|
||||||
.attribs
|
.get(0)
|
||||||
.get(2)
|
.is_some_and(|a| s.0.contains(a))
|
||||||
.map(|str| str.parse().ok())
|
}) {
|
||||||
.flatten()
|
return Ok(false);
|
||||||
!= self.session.attributes.get(2).map(|v| *v)
|
}
|
||||||
{
|
if search_criteria.attribs.get(2).is_some_and(|s| {
|
||||||
return Ok(false);
|
self.session
|
||||||
}
|
.attributes
|
||||||
if search_criteria
|
.get(2)
|
||||||
.attribs
|
.is_some_and(|a| s.0.contains(a))
|
||||||
.get(3)
|
}) {
|
||||||
.map(|str| str.parse().ok())
|
return Ok(false);
|
||||||
.flatten()
|
}
|
||||||
!= self.session.attributes.get(3).map(|v| *v)
|
if search_criteria.attribs.get(3).is_some_and(|s| {
|
||||||
{
|
self.session
|
||||||
return Ok(false);
|
.attributes
|
||||||
|
.get(3)
|
||||||
|
.is_some_and(|a| s.0.contains(a))
|
||||||
|
}) {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,20 @@ use cfg_if::cfg_if;
|
||||||
pub mod account;
|
pub mod account;
|
||||||
pub mod auth_handler;
|
pub mod auth_handler;
|
||||||
pub mod common;
|
pub mod common;
|
||||||
pub mod friends_handler;
|
|
||||||
pub mod matchmake;
|
cfg_if! {
|
||||||
pub mod remote_console;
|
if #[cfg(feature = "friends")]{
|
||||||
pub mod user;
|
pub mod friends_handler;
|
||||||
pub mod datastore;
|
} else {
|
||||||
|
pub mod matchmake;
|
||||||
|
pub mod remote_console;
|
||||||
|
pub mod user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "datastore")] {
|
if #[cfg(feature = "datastore")] {
|
||||||
pub mod s3presigner;
|
pub mod s3presigner;
|
||||||
|
pub mod datastore;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,32 @@
|
||||||
use crate::define_rmc_proto;
|
|
||||||
use crate::nex::common::get_station_urls;
|
|
||||||
use crate::nex::matchmake::{ExtendedMatchmakeSession, MatchmakeManager};
|
|
||||||
use crate::nex::remote_console::RemoteConsole;
|
|
||||||
use crate::rmc::protocols::matchmake::{
|
|
||||||
Matchmake, RawMatchmake, RawMatchmakeInfo, RemoteMatchmake,
|
|
||||||
};
|
|
||||||
use crate::rmc::protocols::nat_traversal::{
|
|
||||||
NatTraversal, RawNatTraversal, RawNatTraversalInfo, RemoteNatTraversal,
|
|
||||||
RemoteNatTraversalConsole,
|
|
||||||
};
|
|
||||||
use rnex_core::PID;
|
use rnex_core::PID;
|
||||||
|
use rnex_core::define_rmc_proto;
|
||||||
use rnex_core::kerberos::KerberosDateTime;
|
use rnex_core::kerberos::KerberosDateTime;
|
||||||
|
use rnex_core::nex::common::get_station_urls;
|
||||||
|
use rnex_core::nex::matchmake::{ExtendedMatchmakeSession, MatchmakeManager};
|
||||||
|
use rnex_core::nex::remote_console::RemoteConsole;
|
||||||
use rnex_core::prudp::station_url::StationUrl;
|
use rnex_core::prudp::station_url::StationUrl;
|
||||||
use rnex_core::prudp::station_url::UrlOptions::{
|
use rnex_core::prudp::station_url::UrlOptions::{
|
||||||
Address, NatFiltering, NatMapping, Port, RVConnectionID,
|
Address, NatFiltering, NatMapping, Port, RVConnectionID,
|
||||||
};
|
};
|
||||||
|
use rnex_core::rmc::protocols::matchmake::{
|
||||||
|
Matchmake, RawMatchmake, RawMatchmakeInfo, RemoteMatchmake,
|
||||||
|
};
|
||||||
use rnex_core::rmc::protocols::matchmake_ext::{
|
use rnex_core::rmc::protocols::matchmake_ext::{
|
||||||
MatchmakeExt, RawMatchmakeExt, RawMatchmakeExtInfo, RemoteMatchmakeExt,
|
MatchmakeExt, RawMatchmakeExt, RawMatchmakeExtInfo, RemoteMatchmakeExt,
|
||||||
};
|
};
|
||||||
use rnex_core::rmc::protocols::matchmake_extension::{
|
use rnex_core::rmc::protocols::matchmake_extension::{
|
||||||
MatchmakeExtension, RawMatchmakeExtension, RawMatchmakeExtensionInfo, RemoteMatchmakeExtension,
|
MatchmakeExtension, RawMatchmakeExtension, RawMatchmakeExtensionInfo, RemoteMatchmakeExtension,
|
||||||
};
|
};
|
||||||
|
use rnex_core::rmc::protocols::nat_traversal::{
|
||||||
|
NatTraversal, RawNatTraversal, RawNatTraversalInfo, RemoteNatTraversal,
|
||||||
|
RemoteNatTraversalConsole,
|
||||||
|
};
|
||||||
|
use rnex_core::rmc::protocols::notifications::notification_types::{
|
||||||
|
END_GATHERING, REQUEST_JOIN_GATHERING,
|
||||||
|
};
|
||||||
use rnex_core::rmc::protocols::ranking::{Ranking, RawRanking, RawRankingInfo, RemoteRanking};
|
use rnex_core::rmc::protocols::ranking::{Ranking, RawRanking, RawRankingInfo, RemoteRanking};
|
||||||
use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure};
|
use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure};
|
||||||
use rnex_core::rmc::protocols::datastore::{DataStore, RawDataStore, RawDataStoreInfo, RemoteDataStore};
|
use rnex_core::rmc::protocols::util::{RawUtility, RawUtilityInfo, RemoteUtility, Utility};
|
||||||
use rnex_core::rmc::response::ErrorCode;
|
use rnex_core::rmc::response::ErrorCode;
|
||||||
use rnex_core::rmc::structures::any::Any;
|
use rnex_core::rmc::structures::any::Any;
|
||||||
use rnex_core::rmc::structures::matchmake::{
|
use rnex_core::rmc::structures::matchmake::{
|
||||||
|
|
@ -33,10 +36,11 @@ use serde::{Deserialize, Serialize};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification};
|
use cfg_if::cfg_if;
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use macros::rmc_struct;
|
use macros::rmc_struct;
|
||||||
use rnex_core::prudp::socket_addr::PRUDPSockAddr;
|
use rnex_core::prudp::socket_addr::PRUDPSockAddr;
|
||||||
|
use rnex_core::rmc::protocols::notifications::{NotificationEvent, RemoteNotification};
|
||||||
use rnex_core::rmc::protocols::ranking::{
|
use rnex_core::rmc::protocols::ranking::{
|
||||||
CompetitionRankingGetParam, CompetitionRankingScoreData, CompetitionRankingScoreInfo,
|
CompetitionRankingGetParam, CompetitionRankingScoreData, CompetitionRankingScoreInfo,
|
||||||
};
|
};
|
||||||
|
|
@ -45,13 +49,13 @@ use rnex_core::rmc::structures::qbuffer::QBuffer;
|
||||||
use rnex_core::rmc::structures::qresult::QResult;
|
use rnex_core::rmc::structures::qresult::QResult;
|
||||||
use rnex_core::rmc::structures::ranking::UploadCompetitionData;
|
use rnex_core::rmc::structures::ranking::UploadCompetitionData;
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
use cfg_if::cfg_if;
|
|
||||||
use rnex_core::rmc::protocols::ranking::{CompetitionRankingScoreData, CompetitionRankingGetParam, CompetitionRankingScoreInfo};
|
|
||||||
use rnex_core::rmc::structures::ranking::{UploadCompetitionData};
|
|
||||||
use tokio::sync::{Mutex, RwLock};
|
use tokio::sync::{Mutex, RwLock};
|
||||||
|
|
||||||
|
use crate::rmc::structures::matchmake::MatchmakeSessionSearchCriteria;
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "datastore")] {
|
if #[cfg(feature = "datastore")] {
|
||||||
|
use rnex_core::rmc::protocols::datastore::{DataStore, RawDataStore, RawDataStoreInfo, RemoteDataStore};
|
||||||
define_rmc_proto!(
|
define_rmc_proto!(
|
||||||
proto UserProtocol{
|
proto UserProtocol{
|
||||||
Secure,
|
Secure,
|
||||||
|
|
@ -60,6 +64,7 @@ cfg_if! {
|
||||||
Matchmake,
|
Matchmake,
|
||||||
NatTraversal,
|
NatTraversal,
|
||||||
Ranking,
|
Ranking,
|
||||||
|
Utility,
|
||||||
DataStore
|
DataStore
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -71,6 +76,7 @@ cfg_if! {
|
||||||
MatchmakeExt,
|
MatchmakeExt,
|
||||||
Matchmake,
|
Matchmake,
|
||||||
NatTraversal,
|
NatTraversal,
|
||||||
|
Utility,
|
||||||
Ranking
|
Ranking
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -99,6 +105,9 @@ impl Secure for User {
|
||||||
let mut users = self.matchmake_manager.users.write().await;
|
let mut users = self.matchmake_manager.users.write().await;
|
||||||
users.insert(cid, self.this.clone());
|
users.insert(cid, self.this.clone());
|
||||||
drop(users);
|
drop(users);
|
||||||
|
let mut users = self.matchmake_manager.users_by_pid.write().await;
|
||||||
|
users.insert(self.pid, self.this.clone());
|
||||||
|
drop(users);
|
||||||
|
|
||||||
let stations = get_station_urls(&station_urls, self.ip, self.pid, cid).await?;
|
let stations = get_station_urls(&station_urls, self.ip, self.pid, cid).await?;
|
||||||
|
|
||||||
|
|
@ -173,6 +182,7 @@ impl MatchmakeExtension for User {
|
||||||
Ok(Vec::new())
|
Ok(Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "v3-5-0")]
|
||||||
async fn update_progress_score(&self, gid: u32, progress: u8) -> Result<(), ErrorCode> {
|
async fn update_progress_score(&self, gid: u32, progress: u8) -> Result<(), ErrorCode> {
|
||||||
let session = self.matchmake_manager.get_session(gid).await?;
|
let session = self.matchmake_manager.get_session(gid).await?;
|
||||||
|
|
||||||
|
|
@ -250,10 +260,10 @@ impl MatchmakeExtension for User {
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut session = session.lock().await;
|
let mut session = session.lock().await;
|
||||||
if session.session.user_password_enabled {
|
|
||||||
if join_session_param.user_password != session.session.user_password {
|
#[cfg(feature = "v3-5-0")]
|
||||||
return Err(ErrorCode::RendezVous_InvalidPassword);
|
if join_session_param.user_password != session.session.user_password {
|
||||||
}
|
return Err(ErrorCode::RendezVous_InvalidPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
session
|
session
|
||||||
|
|
@ -400,9 +410,147 @@ impl MatchmakeExtension for User {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn create_matchmake_session(
|
||||||
|
&self,
|
||||||
|
gathering: Any,
|
||||||
|
message: String,
|
||||||
|
) -> Result<(u32, Vec<u8>), ErrorCode> {
|
||||||
|
info!("gathering: {:?}", gathering);
|
||||||
|
let Some(Ok(session)): Option<Result<MatchmakeSession, _>> = gathering.try_get() else {
|
||||||
|
return Err(ErrorCode::Core_InvalidArgument);
|
||||||
|
};
|
||||||
|
|
||||||
|
let session = self
|
||||||
|
.create_matchmake_session_with_param(CreateMatchmakeSessionParam {
|
||||||
|
matchmake_session: session,
|
||||||
|
additional_participants: vec![],
|
||||||
|
gid_for_participation_check: 0,
|
||||||
|
create_matchmake_session_option: 0,
|
||||||
|
join_message: message,
|
||||||
|
participation_count: 1,
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok((session.gathering.self_gid, session.session_key))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_friend_notification_data(
|
||||||
|
&self,
|
||||||
|
_ty: i32,
|
||||||
|
) -> Result<Vec<NotificationEvent>, ErrorCode> {
|
||||||
|
Ok(vec![])
|
||||||
|
}
|
||||||
|
async fn update_notification_data(
|
||||||
|
&self,
|
||||||
|
ty: u32,
|
||||||
|
param_1: u32,
|
||||||
|
param_2: u32,
|
||||||
|
str_param: String,
|
||||||
|
) -> Result<(), ErrorCode> {
|
||||||
|
let recpipent = param_2;
|
||||||
|
let Some(user) = self
|
||||||
|
.matchmake_manager
|
||||||
|
.users_by_pid
|
||||||
|
.read()
|
||||||
|
.await
|
||||||
|
.get(&recpipent)
|
||||||
|
.and_then(|v| v.upgrade())
|
||||||
|
else {
|
||||||
|
return Err(ErrorCode::Core_InvalidArgument);
|
||||||
|
};
|
||||||
|
println!("notif ty : {}", ty);
|
||||||
|
match ty {
|
||||||
|
REQUEST_JOIN_GATHERING => {
|
||||||
|
user.remote
|
||||||
|
.process_notification_event(NotificationEvent {
|
||||||
|
pid_source: self.pid,
|
||||||
|
notif_type: REQUEST_JOIN_GATHERING * 1000,
|
||||||
|
param_1,
|
||||||
|
param_2,
|
||||||
|
#[cfg(feature = "third-notif-param")]
|
||||||
|
param_3: 0,
|
||||||
|
str_param,
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
END_GATHERING => {
|
||||||
|
user.remote
|
||||||
|
.process_notification_event(NotificationEvent {
|
||||||
|
pid_source: self.pid,
|
||||||
|
notif_type: END_GATHERING * 1000,
|
||||||
|
param_1,
|
||||||
|
param_2,
|
||||||
|
#[cfg(feature = "third-notif-param")]
|
||||||
|
param_3: 0,
|
||||||
|
str_param,
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(ErrorCode::Core_InvalidArgument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn join_matchmake_session_ex(
|
||||||
|
&self,
|
||||||
|
gid: u32,
|
||||||
|
message: String,
|
||||||
|
_dont_care_block_list: bool,
|
||||||
|
//participation_count: u16,
|
||||||
|
) -> Result<Vec<u8>, ErrorCode> {
|
||||||
|
let sess = self.matchmake_manager.get_session(gid).await?;
|
||||||
|
let mut sess = sess.lock().await;
|
||||||
|
sess.add_players(&[self.this.clone()], message).await;
|
||||||
|
|
||||||
|
Ok(sess.session.session_key.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn auto_matchmake_with_search_criteria_postpone(
|
||||||
|
&self,
|
||||||
|
criteria: Vec<MatchmakeSessionSearchCriteria>,
|
||||||
|
gathering: Any,
|
||||||
|
join_message: String,
|
||||||
|
) -> Result<Any, ErrorCode> {
|
||||||
|
let session: MatchmakeSession = gathering
|
||||||
|
.try_get()
|
||||||
|
.map(|v| v.ok())
|
||||||
|
.flatten()
|
||||||
|
.ok_or(ErrorCode::Core_InvalidArgument)?;
|
||||||
|
|
||||||
|
println!("{:?}", criteria);
|
||||||
|
|
||||||
|
let session = self
|
||||||
|
.auto_matchmake_with_param_postpone(AutoMatchmakeParam {
|
||||||
|
matchmake_session: session,
|
||||||
|
additional_participants: vec![],
|
||||||
|
gid_for_participation_check: 0,
|
||||||
|
auto_matchmake_option: 0,
|
||||||
|
join_message,
|
||||||
|
participation_count: 0,
|
||||||
|
search_criteria: criteria,
|
||||||
|
target_gids: vec![],
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let any = Any::new(&session).map_err(|_| ErrorCode::Core_SystemError)?;
|
||||||
|
|
||||||
|
Ok(any)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Matchmake for User {
|
impl Matchmake for User {
|
||||||
|
async fn find_by_single_id(&self, gid: u32) -> Result<(bool, Any), ErrorCode> {
|
||||||
|
let s = self.matchmake_manager.get_session(gid).await?;
|
||||||
|
let s = s.lock().await;
|
||||||
|
Ok((
|
||||||
|
true,
|
||||||
|
Any::new(&s.session).map_err(|_| ErrorCode::Custom_Unknown)?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
async fn unregister_gathering(&self, _gid: u32) -> Result<bool, ErrorCode> {
|
async fn unregister_gathering(&self, _gid: u32) -> Result<bool, ErrorCode> {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
@ -452,6 +600,7 @@ impl Matchmake for User {
|
||||||
pid_source: self.pid,
|
pid_source: self.pid,
|
||||||
param_1: gid as PID,
|
param_1: gid as PID,
|
||||||
param_2: self.pid,
|
param_2: self.pid,
|
||||||
|
#[cfg(feature = "third-notif-param")]
|
||||||
param_3: 0,
|
param_3: 0,
|
||||||
str_param: "".to_string(),
|
str_param: "".to_string(),
|
||||||
})
|
})
|
||||||
|
|
@ -473,6 +622,7 @@ impl Matchmake for User {
|
||||||
pid_source: self.pid,
|
pid_source: self.pid,
|
||||||
param_1: gid as PID,
|
param_1: gid as PID,
|
||||||
param_2: self.pid,
|
param_2: self.pid,
|
||||||
|
#[cfg(feature = "third-notif-param")]
|
||||||
param_3: 0,
|
param_3: 0,
|
||||||
str_param: "".to_string(),
|
str_param: "".to_string(),
|
||||||
})
|
})
|
||||||
|
|
@ -508,6 +658,7 @@ impl Matchmake for User {
|
||||||
pid_source: self.pid,
|
pid_source: self.pid,
|
||||||
param_1: gid as PID,
|
param_1: gid as PID,
|
||||||
param_2: *candidate as PID,
|
param_2: *candidate as PID,
|
||||||
|
#[cfg(feature = "third-notif-param")]
|
||||||
param_3: 0,
|
param_3: 0,
|
||||||
str_param: "".to_string(),
|
str_param: "".to_string(),
|
||||||
})
|
})
|
||||||
|
|
@ -647,6 +798,12 @@ fn fetch_team_votes(fest_id: u32) -> Result<Vec<u32>, ErrorCode> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Utility for User {
|
||||||
|
async fn acquire_nex_unique_id(&self) -> Result<u64, ErrorCode> {
|
||||||
|
return Ok(rand::random());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Ranking for User {
|
impl Ranking for User {
|
||||||
async fn competition_ranking_get_param(
|
async fn competition_ranking_get_param(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -673,16 +830,22 @@ impl Ranking for User {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let offset = param.range.offset as usize;
|
||||||
|
let size = param.range.size as usize;
|
||||||
|
|
||||||
|
let start = offset.min(results.len());
|
||||||
|
let end = (start + size).min(results.len());
|
||||||
|
|
||||||
let team_votes = fetch_team_votes(fest_id)?;
|
let team_votes = fetch_team_votes(fest_id)?;
|
||||||
let mut wins = vec![0u32, 0u32];
|
let mut wins = vec![0u32, 0u32];
|
||||||
for r in &results {
|
for r in &results {
|
||||||
let won_team = r.team_id ^ (!r.team_win);
|
let won_team = (r.team_id ^ (!r.team_win)) & 1;
|
||||||
if let Some(team) = wins.get_mut(won_team as usize) {
|
if let Some(team) = wins.get_mut(won_team as usize) {
|
||||||
*team += 1
|
*team += 1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let score_data: Vec<CompetitionRankingScoreData> = results
|
let score_data: Vec<CompetitionRankingScoreData> = results[start..end]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|r| CompetitionRankingScoreData {
|
.map(|r| CompetitionRankingScoreData {
|
||||||
unk: 1,
|
unk: 1,
|
||||||
|
|
@ -702,6 +865,8 @@ impl Ranking for User {
|
||||||
team_votes,
|
team_votes,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
println!("range: {:?}", param.range);
|
||||||
|
|
||||||
Ok(vec![info])
|
Ok(vec![info])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use typenum::U16;
|
||||||
use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions};
|
use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
kerberos::{SESSION_KEY_LENGTH, SESSION_KEY_LENGTH_TY, TicketInternalData, derive_key},
|
kerberos::{SESSION_KEY_LENGTH, SessionLengthTy, TicketInternalData, derive_key},
|
||||||
nex::account::Account,
|
nex::account::Account,
|
||||||
rmc::structures::RmcSerialize,
|
rmc::structures::RmcSerialize,
|
||||||
};
|
};
|
||||||
|
|
@ -53,7 +53,7 @@ pub fn read_secure_connection_data(
|
||||||
let request_data_length = request_data.len();
|
let request_data_length = request_data.len();
|
||||||
let request_data = &mut request_data[0..request_data_length - 0x10];
|
let request_data = &mut request_data[0..request_data_length - 0x10];
|
||||||
|
|
||||||
let mut rc4: StreamCipherCoreWrapper<Rc4Core<SESSION_KEY_LENGTH_TY>> =
|
let mut rc4: StreamCipherCoreWrapper<Rc4Core<SessionLengthTy>> =
|
||||||
Rc4::new_from_slice(&session_key).expect("unable to init rc4 keystream");
|
Rc4::new_from_slice(&session_key).expect("unable to init rc4 keystream");
|
||||||
|
|
||||||
rc4.apply_keystream(request_data);
|
rc4.apply_keystream(request_data);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use std::{
|
use std::fmt::{Debug, Formatter};
|
||||||
fmt::{Debug, Formatter},
|
|
||||||
slice,
|
|
||||||
};
|
|
||||||
use v_byte_helpers::SwapEndian;
|
use v_byte_helpers::SwapEndian;
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,11 @@ use rnex_core::rmc::structures::qresult::QResult;
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "nx")]{
|
if #[cfg(feature = "nx")]{
|
||||||
type LOGIN_EX_RET = (QResult, PID, Vec<u8>, ConnectionData, String, String);
|
type LoginExRet = (QResult, PID, Vec<u8>, ConnectionData, String, String);
|
||||||
type REQUEST_TICKET_RET = (QResult, Vec<u8>, String);
|
type RequestTicketRet = (QResult, Vec<u8>, String);
|
||||||
} else {
|
} else {
|
||||||
type LOGIN_EX_RET = (QResult, PID, Vec<u8>, ConnectionData, String);
|
type LoginExRet = (QResult, PID, Vec<u8>, ConnectionData, String);
|
||||||
type REQUEST_TICKET_RET = (QResult, Vec<u8>);
|
type RequestTicketRet = (QResult, Vec<u8>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,14 +31,14 @@ pub trait Auth {
|
||||||
/// representation of the `LoginEx` method(for details see the
|
/// representation of the `LoginEx` method(for details see the
|
||||||
/// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol))
|
/// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol))
|
||||||
#[method_id(2)]
|
#[method_id(2)]
|
||||||
async fn login_ex(&self, name: String, extra_data: Any) -> Result<LOGIN_EX_RET, ErrorCode>;
|
async fn login_ex(&self, name: String, extra_data: Any) -> Result<LoginExRet, ErrorCode>;
|
||||||
|
|
||||||
#[method_id(3)]
|
#[method_id(3)]
|
||||||
async fn request_ticket(
|
async fn request_ticket(
|
||||||
&self,
|
&self,
|
||||||
source_pid: PID,
|
source_pid: PID,
|
||||||
destination_pid: PID,
|
destination_pid: PID,
|
||||||
) -> Result<REQUEST_TICKET_RET, ErrorCode>;
|
) -> Result<RequestTicketRet, ErrorCode>;
|
||||||
|
|
||||||
/// representation of the `RequestTicket` method(for details see the
|
/// representation of the `RequestTicket` method(for details see the
|
||||||
/// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol))
|
/// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol))
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use macros::{method_id, rmc_proto, RmcSerialize, rmc_struct};
|
use macros::{RmcSerialize, method_id, rmc_proto};
|
||||||
use rnex_core::rmc::structures::qbuffer::QBuffer;
|
|
||||||
use rnex_core::rmc::response::ErrorCode;
|
|
||||||
use rnex_core::rmc::structures::qresult::QResult;
|
|
||||||
use rnex_core::kerberos::KerberosDateTime;
|
|
||||||
use rnex_core::PID;
|
use rnex_core::PID;
|
||||||
|
use rnex_core::kerberos::KerberosDateTime;
|
||||||
|
use rnex_core::rmc::response::ErrorCode;
|
||||||
|
use rnex_core::rmc::structures::qbuffer::QBuffer;
|
||||||
|
use rnex_core::rmc::structures::qresult::QResult;
|
||||||
use rnex_core::rmc::structures::resultsrange::ResultsRange;
|
use rnex_core::rmc::structures::resultsrange::ResultsRange;
|
||||||
|
|
||||||
#[derive(RmcSerialize, Clone, Debug, Default)]
|
#[derive(RmcSerialize, Clone, Debug, Default)]
|
||||||
|
|
@ -78,7 +78,7 @@ pub struct RatingInitParam {
|
||||||
pub range_min: i32,
|
pub range_min: i32,
|
||||||
pub range_max: i32,
|
pub range_max: i32,
|
||||||
pub period_hour: i8,
|
pub period_hour: i8,
|
||||||
pub period_duration: i16
|
pub period_duration: i16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RmcSerialize, Clone)]
|
#[derive(RmcSerialize, Clone)]
|
||||||
|
|
@ -214,27 +214,53 @@ pub struct DataStoreSearchParam {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rmc_proto(115)]
|
#[rmc_proto(115)]
|
||||||
pub trait DataStore{
|
pub trait DataStore {
|
||||||
#[method_id(8)]
|
#[method_id(8)]
|
||||||
async fn get_meta(&self, metaparam: GetMetaParam) -> Result<GetMetaInfo, ErrorCode>;
|
async fn get_meta(&self, metaparam: GetMetaParam) -> Result<GetMetaInfo, ErrorCode>;
|
||||||
#[method_id(36)]
|
#[method_id(36)]
|
||||||
async fn get_metas_multiple_param(&self, params: Vec<GetMetaParam>) -> Result<(Vec<GetMetaInfo>, Vec<QResult>), ErrorCode>;
|
async fn get_metas_multiple_param(
|
||||||
|
&self,
|
||||||
|
params: Vec<GetMetaParam>,
|
||||||
|
) -> Result<(Vec<GetMetaInfo>, Vec<QResult>), ErrorCode>;
|
||||||
#[method_id(24)]
|
#[method_id(24)]
|
||||||
async fn prepare_post_object(&self, postparam: PreparePostParam) -> Result<ReqPostInfo, ErrorCode>;
|
async fn prepare_post_object(
|
||||||
|
&self,
|
||||||
|
postparam: PreparePostParam,
|
||||||
|
) -> Result<ReqPostInfo, ErrorCode>;
|
||||||
#[method_id(26)]
|
#[method_id(26)]
|
||||||
async fn complete_post_object(&self, completeparam: CompletePostParam) -> Result<(), ErrorCode>;
|
async fn complete_post_object(&self, completeparam: CompletePostParam)
|
||||||
|
-> Result<(), ErrorCode>;
|
||||||
#[method_id(48)]
|
#[method_id(48)]
|
||||||
async fn rate_custom_ranking(&self, rankingparam: Vec<RateCustomRankingParam>) -> Result<(), ErrorCode>;
|
async fn rate_custom_ranking(
|
||||||
|
&self,
|
||||||
|
rankingparam: Vec<RateCustomRankingParam>,
|
||||||
|
) -> Result<(), ErrorCode>;
|
||||||
#[method_id(61)]
|
#[method_id(61)]
|
||||||
async fn get_application_config(&self, appid: u32) -> Result<Vec<i32>, ErrorCode>;
|
async fn get_application_config(&self, appid: u32) -> Result<Vec<i32>, ErrorCode>;
|
||||||
#[method_id(50)]
|
#[method_id(50)]
|
||||||
async fn get_custom_ranking_by_data_id(&self, custom_ranking_param: DataStoreGetCustomRankingByDataIDParam) -> Result<(Vec<DataStoreCustomRankingResult>, Vec<QResult>), ErrorCode>;
|
async fn get_custom_ranking_by_data_id(
|
||||||
|
&self,
|
||||||
|
custom_ranking_param: DataStoreGetCustomRankingByDataIDParam,
|
||||||
|
) -> Result<(Vec<DataStoreCustomRankingResult>, Vec<QResult>), ErrorCode>;
|
||||||
#[method_id(54)]
|
#[method_id(54)]
|
||||||
async fn get_buffer_queue(&self, bufferparam: BufferQueueParam) -> Result<Vec<QBuffer>, ErrorCode>;
|
async fn get_buffer_queue(
|
||||||
|
&self,
|
||||||
|
bufferparam: BufferQueueParam,
|
||||||
|
) -> Result<Vec<QBuffer>, ErrorCode>;
|
||||||
#[method_id(25)]
|
#[method_id(25)]
|
||||||
async fn prepare_get_object(&self, prepare_get_param: DataStorePrepareGetParam) -> Result<DataStoreReqGetInfo, ErrorCode>;
|
async fn prepare_get_object(
|
||||||
|
&self,
|
||||||
|
prepare_get_param: DataStorePrepareGetParam,
|
||||||
|
) -> Result<DataStoreReqGetInfo, ErrorCode>;
|
||||||
#[method_id(65)]
|
#[method_id(65)]
|
||||||
async fn followings_latest_course_search_object(&self, course_search_param: DataStoreSearchParam, extra_data: Vec<String>) -> Result<Vec<DataStoreCustomRankingResult>, ErrorCode>;
|
async fn followings_latest_course_search_object(
|
||||||
|
&self,
|
||||||
|
course_search_param: DataStoreSearchParam,
|
||||||
|
extra_data: Vec<String>,
|
||||||
|
) -> Result<Vec<DataStoreCustomRankingResult>, ErrorCode>;
|
||||||
#[method_id(74)]
|
#[method_id(74)]
|
||||||
async fn get_application_config_string(&self, application_id: u32) -> Result<Vec<String>, ErrorCode>;
|
async fn get_application_config_string(
|
||||||
}
|
&self,
|
||||||
|
application_id: u32,
|
||||||
|
) -> Result<Vec<String>, ErrorCode>;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use macros::{RmcSerialize, method_id, rmc_proto};
|
||||||
|
|
||||||
use rnex_core::{kerberos::KerberosDateTime, rmc::response::ErrorCode};
|
use rnex_core::{kerberos::KerberosDateTime, rmc::response::ErrorCode};
|
||||||
|
|
||||||
use rnex_core::rmc::structures::{data::Data, rmc_struct};
|
use rnex_core::rmc::structures::data::Data;
|
||||||
|
|
||||||
#[derive(RmcSerialize, Debug, Clone)]
|
#[derive(RmcSerialize, Debug, Clone)]
|
||||||
#[rmc_struct(0)]
|
#[rmc_struct(0)]
|
||||||
|
|
@ -67,7 +67,7 @@ pub struct NintendoPresenceV2 {
|
||||||
pub unk6: u8,
|
pub unk6: u8,
|
||||||
pub unk7: u8,
|
pub unk7: u8,
|
||||||
}
|
}
|
||||||
#[derive(RmcSerialize)]
|
#[derive(RmcSerialize, Clone, Debug)]
|
||||||
#[rmc_struct(0)]
|
#[rmc_struct(0)]
|
||||||
pub struct PrincipalPreference {
|
pub struct PrincipalPreference {
|
||||||
#[extends]
|
#[extends]
|
||||||
|
|
@ -171,6 +171,8 @@ pub trait Friends {
|
||||||
>;
|
>;
|
||||||
#[method_id(13)]
|
#[method_id(13)]
|
||||||
async fn update_presence(&self, presence: NintendoPresenceV2) -> Result<(), ErrorCode>;
|
async fn update_presence(&self, presence: NintendoPresenceV2) -> Result<(), ErrorCode>;
|
||||||
|
#[method_id(16)]
|
||||||
|
async fn update_preference(&self, preference: PrincipalPreference) -> Result<(), ErrorCode>;
|
||||||
#[method_id(18)]
|
#[method_id(18)]
|
||||||
async fn delete_persistent_notification(
|
async fn delete_persistent_notification(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,14 @@ use rnex_core::rmc::response::ErrorCode;
|
||||||
|
|
||||||
use rnex_core::PID;
|
use rnex_core::PID;
|
||||||
|
|
||||||
|
use crate::rmc::structures::any::Any;
|
||||||
|
|
||||||
#[rmc_proto(21)]
|
#[rmc_proto(21)]
|
||||||
pub trait Matchmake {
|
pub trait Matchmake {
|
||||||
#[method_id(2)]
|
#[method_id(2)]
|
||||||
async fn unregister_gathering(&self, gid: u32) -> Result<bool, ErrorCode>;
|
async fn unregister_gathering(&self, gid: u32) -> Result<bool, ErrorCode>;
|
||||||
|
#[method_id(21)]
|
||||||
|
async fn find_by_single_id(&self, gid: u32) -> Result<(bool, Any), ErrorCode>;
|
||||||
#[method_id(41)]
|
#[method_id(41)]
|
||||||
async fn get_session_urls(&self, gid: u32) -> Result<Vec<StationUrl>, ErrorCode>;
|
async fn get_session_urls(&self, gid: u32) -> Result<Vec<StationUrl>, ErrorCode>;
|
||||||
#[method_id(42)]
|
#[method_id(42)]
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,94 @@
|
||||||
use macros::{method_id, rmc_proto};
|
use macros::{method_id, rmc_proto};
|
||||||
use rnex_core::rmc::response::ErrorCode;
|
use rnex_core::rmc::response::ErrorCode;
|
||||||
use rnex_core::rmc::structures::matchmake::{AutoMatchmakeParam, CreateMatchmakeSessionParam, JoinMatchmakeSessionParam, MatchmakeSession};
|
use rnex_core::rmc::structures::matchmake::{
|
||||||
|
AutoMatchmakeParam, CreateMatchmakeSessionParam, JoinMatchmakeSessionParam, MatchmakeSession,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::rmc::protocols::notifications::NotificationEvent;
|
||||||
|
use crate::rmc::structures::any::Any;
|
||||||
|
use crate::rmc::structures::matchmake::MatchmakeSessionSearchCriteria;
|
||||||
|
|
||||||
#[rmc_proto(109)]
|
#[rmc_proto(109)]
|
||||||
pub trait MatchmakeExtension{
|
pub trait MatchmakeExtension {
|
||||||
#[method_id(1)]
|
#[method_id(1)]
|
||||||
async fn close_participation(&self, gid: u32) -> Result<(), ErrorCode>;
|
async fn close_participation(&self, gid: u32) -> Result<(), ErrorCode>;
|
||||||
|
|
||||||
#[method_id(2)]
|
#[method_id(2)]
|
||||||
async fn open_participation(&self, gid: u32) -> Result<(), ErrorCode>;
|
async fn open_participation(&self, gid: u32) -> Result<(), ErrorCode>;
|
||||||
|
#[method_id(6)]
|
||||||
|
async fn create_matchmake_session(
|
||||||
|
&self,
|
||||||
|
gathering: Any,
|
||||||
|
message: String,
|
||||||
|
) -> Result<(u32, Vec<u8>), ErrorCode>;
|
||||||
|
|
||||||
|
#[method_id(9)]
|
||||||
|
async fn update_notification_data(
|
||||||
|
&self,
|
||||||
|
ty: u32,
|
||||||
|
param1: u32,
|
||||||
|
param2: u32,
|
||||||
|
str_param: String,
|
||||||
|
) -> Result<(), ErrorCode>;
|
||||||
|
|
||||||
|
#[method_id(10)]
|
||||||
|
async fn get_friend_notification_data(
|
||||||
|
&self,
|
||||||
|
ty: i32,
|
||||||
|
) -> Result<Vec<NotificationEvent>, ErrorCode>;
|
||||||
|
#[method_id(15)]
|
||||||
|
async fn auto_matchmake_with_search_criteria_postpone(
|
||||||
|
&self,
|
||||||
|
criteria: Vec<MatchmakeSessionSearchCriteria>,
|
||||||
|
gathering: Any,
|
||||||
|
join_msg: String,
|
||||||
|
) -> Result<Any, ErrorCode>;
|
||||||
|
|
||||||
|
#[method_id(30)]
|
||||||
|
async fn join_matchmake_session_ex(
|
||||||
|
&self,
|
||||||
|
gid: u32,
|
||||||
|
message: String,
|
||||||
|
dont_care_block_list: bool,
|
||||||
|
// this is to cheat support for v3-3-0
|
||||||
|
//participation_count: u16,
|
||||||
|
) -> Result<Vec<u8>, ErrorCode>;
|
||||||
|
|
||||||
#[method_id(8)]
|
#[method_id(8)]
|
||||||
async fn modify_current_game_attribute(&self, gid: u32, attrib_index: u32, attrib_val: u32) -> Result<(), ErrorCode>;
|
async fn modify_current_game_attribute(
|
||||||
|
&self,
|
||||||
|
gid: u32,
|
||||||
|
attrib_index: u32,
|
||||||
|
attrib_val: u32,
|
||||||
|
) -> Result<(), ErrorCode>;
|
||||||
|
|
||||||
#[method_id(16)]
|
#[method_id(16)]
|
||||||
async fn get_playing_session(&self, pids: Vec<u32>) -> Result<Vec<()>, ErrorCode>;
|
async fn get_playing_session(&self, pids: Vec<u32>) -> Result<Vec<()>, ErrorCode>;
|
||||||
|
|
||||||
#[method_id(34)]
|
#[method_id(34)]
|
||||||
|
#[cfg(feature = "v3-5-0")]
|
||||||
async fn update_progress_score(&self, gid: u32, progress: u8) -> Result<(), ErrorCode>;
|
async fn update_progress_score(&self, gid: u32, progress: u8) -> Result<(), ErrorCode>;
|
||||||
#[method_id(38)]
|
#[method_id(38)]
|
||||||
async fn create_matchmake_session_with_param(&self, session: CreateMatchmakeSessionParam) -> Result<MatchmakeSession, ErrorCode>;
|
async fn create_matchmake_session_with_param(
|
||||||
|
&self,
|
||||||
|
session: CreateMatchmakeSessionParam,
|
||||||
|
) -> Result<MatchmakeSession, ErrorCode>;
|
||||||
|
|
||||||
#[method_id(39)]
|
#[method_id(39)]
|
||||||
async fn join_matchmake_session_with_param(&self, session: JoinMatchmakeSessionParam) -> Result<MatchmakeSession, ErrorCode>;
|
async fn join_matchmake_session_with_param(
|
||||||
|
&self,
|
||||||
|
session: JoinMatchmakeSessionParam,
|
||||||
|
) -> Result<MatchmakeSession, ErrorCode>;
|
||||||
|
|
||||||
#[method_id(40)]
|
#[method_id(40)]
|
||||||
async fn auto_matchmake_with_param_postpone(&self, session: AutoMatchmakeParam) -> Result<MatchmakeSession, ErrorCode>;
|
async fn auto_matchmake_with_param_postpone(
|
||||||
|
&self,
|
||||||
|
session: AutoMatchmakeParam,
|
||||||
|
) -> Result<MatchmakeSession, ErrorCode>;
|
||||||
|
|
||||||
#[method_id(41)]
|
#[method_id(41)]
|
||||||
async fn find_matchmake_session_by_gathering_id_detail(&self, gid: u32) -> Result<MatchmakeSession, ErrorCode>;
|
async fn find_matchmake_session_by_gathering_id_detail(
|
||||||
}
|
&self,
|
||||||
|
gid: u32,
|
||||||
|
) -> Result<MatchmakeSession, ErrorCode>;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
pub mod account_management;
|
pub mod account_management;
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
|
pub mod datastore;
|
||||||
pub mod friends;
|
pub mod friends;
|
||||||
pub mod matchmake;
|
pub mod matchmake;
|
||||||
pub mod matchmake_ext;
|
pub mod matchmake_ext;
|
||||||
|
|
@ -11,7 +12,7 @@ pub mod nintendo_notification;
|
||||||
pub mod notifications;
|
pub mod notifications;
|
||||||
pub mod ranking;
|
pub mod ranking;
|
||||||
pub mod secure;
|
pub mod secure;
|
||||||
pub mod datastore;
|
pub mod util;
|
||||||
|
|
||||||
use crate::result::ResultExtension;
|
use crate::result::ResultExtension;
|
||||||
use crate::rmc::message::RMCMessage;
|
use crate::rmc::message::RMCMessage;
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,37 @@
|
||||||
use macros::{RmcSerialize, method_id, rmc_proto, rmc_struct};
|
use macros::{RmcSerialize, method_id, rmc_proto};
|
||||||
|
|
||||||
use rnex_core::PID;
|
use rnex_core::PID;
|
||||||
|
|
||||||
pub mod notification_types {
|
pub mod notification_types {
|
||||||
pub const OWNERSHIP_CHANGED: u32 = 4000;
|
pub const OWNERSHIP_CHANGED: u32 = 4000;
|
||||||
pub const HOST_CHANGED: u32 = 110000;
|
pub const HOST_CHANGED: u32 = 110000;
|
||||||
|
pub const REQUEST_JOIN_GATHERING: u32 = 101;
|
||||||
|
pub const END_GATHERING: u32 = 102;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RmcSerialize, Debug, Default, Clone)]
|
cfg_if::cfg_if! {
|
||||||
#[rmc_struct(0)]
|
if #[cfg(feature = "third-notif-param")]{
|
||||||
pub struct NotificationEvent {
|
#[derive(RmcSerialize, Debug, Default, Clone)]
|
||||||
pub pid_source: PID,
|
#[rmc_struct(0)]
|
||||||
pub notif_type: u32,
|
pub struct NotificationEvent {
|
||||||
pub param_1: PID,
|
pub pid_source: PID,
|
||||||
pub param_2: PID,
|
pub notif_type: u32,
|
||||||
pub str_param: String,
|
pub param_1: PID,
|
||||||
pub param_3: PID,
|
pub param_2: PID,
|
||||||
|
pub str_param: String,
|
||||||
|
pub param_3: PID,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#[derive(RmcSerialize, Debug, Default, Clone)]
|
||||||
|
#[rmc_struct(0)]
|
||||||
|
pub struct NotificationEvent {
|
||||||
|
pub pid_source: PID,
|
||||||
|
pub notif_type: u32,
|
||||||
|
pub param_1: PID,
|
||||||
|
pub param_2: PID,
|
||||||
|
pub str_param: String,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rmc_proto(14, NoReturn)]
|
#[rmc_proto(14, NoReturn)]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use macros::{rmc_struct, rmc_proto, RmcSerialize, method_id};
|
use macros::{RmcSerialize, method_id, rmc_proto};
|
||||||
|
|
||||||
use rnex_core::kerberos::KerberosDateTime;
|
use rnex_core::kerberos::KerberosDateTime;
|
||||||
use rnex_core::rmc::structures::qbuffer::QBuffer;
|
use rnex_core::rmc::structures::qbuffer::QBuffer;
|
||||||
|
|
@ -16,29 +16,35 @@ pub struct CompetitionRankingGetParam {
|
||||||
|
|
||||||
#[derive(RmcSerialize, Debug, Default, Clone)]
|
#[derive(RmcSerialize, Debug, Default, Clone)]
|
||||||
#[rmc_struct(0)]
|
#[rmc_struct(0)]
|
||||||
pub struct CompetitionRankingScoreInfo{
|
pub struct CompetitionRankingScoreInfo {
|
||||||
pub fest_id: u32,
|
pub fest_id: u32,
|
||||||
pub score_data: Vec<CompetitionRankingScoreData>,
|
pub score_data: Vec<CompetitionRankingScoreData>,
|
||||||
pub unk: u32,
|
pub unk: u32,
|
||||||
pub team_wins: Vec<u32>,
|
pub team_wins: Vec<u32>,
|
||||||
pub team_votes: Vec<u32>
|
pub team_votes: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RmcSerialize, Debug, Clone)]
|
#[derive(RmcSerialize, Debug, Clone)]
|
||||||
#[rmc_struct(0)]
|
#[rmc_struct(0)]
|
||||||
pub struct CompetitionRankingScoreData{
|
pub struct CompetitionRankingScoreData {
|
||||||
pub unk: u32,
|
pub unk: u32,
|
||||||
pub pid: u32,
|
pub pid: u32,
|
||||||
pub score: u32,
|
pub score: u32,
|
||||||
pub modified: KerberosDateTime,
|
pub modified: KerberosDateTime,
|
||||||
pub unk2: u8,
|
pub unk2: u8,
|
||||||
pub appdata: QBuffer
|
pub appdata: QBuffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rmc_proto(112)]
|
#[rmc_proto(112)]
|
||||||
pub trait Ranking{
|
pub trait Ranking {
|
||||||
#[method_id(16)]
|
#[method_id(16)]
|
||||||
async fn competition_ranking_get_param(&self, param: CompetitionRankingGetParam) -> Result<Vec<CompetitionRankingScoreInfo>,ErrorCode>;
|
async fn competition_ranking_get_param(
|
||||||
|
&self,
|
||||||
|
param: CompetitionRankingGetParam,
|
||||||
|
) -> Result<Vec<CompetitionRankingScoreInfo>, ErrorCode>;
|
||||||
#[method_id(18)]
|
#[method_id(18)]
|
||||||
async fn upload_competition_ranking_score(&self, param: UploadCompetitionData) -> Result<bool, ErrorCode>;
|
async fn upload_competition_ranking_score(
|
||||||
|
&self,
|
||||||
|
param: UploadCompetitionData,
|
||||||
|
) -> Result<bool, ErrorCode>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
9
rnex-core/src/rmc/protocols/util.rs
Normal file
9
rnex-core/src/rmc/protocols/util.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
use macros::{method_id, rmc_proto};
|
||||||
|
|
||||||
|
use rnex_core::rmc::response::ErrorCode;
|
||||||
|
|
||||||
|
#[rmc_proto(110)]
|
||||||
|
pub trait Utility {
|
||||||
|
#[method_id(1)]
|
||||||
|
async fn acquire_nex_unique_id(&self) -> Result<u64, ErrorCode>;
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,7 @@ use crate::rmc::response::ErrorCode::Core_Exception;
|
||||||
use crate::rmc::structures::qresult::ERROR_MASK;
|
use crate::rmc::structures::qresult::ERROR_MASK;
|
||||||
use crate::util::SendingBufferConnection;
|
use crate::util::SendingBufferConnection;
|
||||||
use bytemuck::bytes_of;
|
use bytemuck::bytes_of;
|
||||||
use log::error;
|
use log::{error, warn};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{Read, Seek, Write};
|
use std::io::{Read, Seek, Write};
|
||||||
use std::mem::transmute;
|
use std::mem::transmute;
|
||||||
|
|
@ -157,10 +157,13 @@ pub async fn send_result(
|
||||||
method_id,
|
method_id,
|
||||||
data: v,
|
data: v,
|
||||||
},
|
},
|
||||||
Err(e) => RMCResponseResult::Error {
|
Err(e) => {
|
||||||
call_id,
|
warn!("error occurred during call: {:?}", e);
|
||||||
error_code: e.into(),
|
RMCResponseResult::Error {
|
||||||
},
|
call_id,
|
||||||
|
error_code: e.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let response = RMCResponse {
|
let response = RMCResponse {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
|
use cfg_if::cfg_if;
|
||||||
use macros::RmcSerialize;
|
use macros::RmcSerialize;
|
||||||
use rnex_core::kerberos::KerberosDateTime;
|
use rnex_core::kerberos::KerberosDateTime;
|
||||||
use rnex_core::rmc::structures::variant::Variant;
|
use rnex_core::rmc::structures::variant::Variant;
|
||||||
|
|
||||||
use rnex_core::PID;
|
use rnex_core::PID;
|
||||||
|
|
||||||
|
use crate::rmc::structures::string_set::StringSet;
|
||||||
|
|
||||||
// rmc structure
|
// rmc structure
|
||||||
#[derive(RmcSerialize, Debug, Clone, Default)]
|
#[derive(RmcSerialize, Debug, Clone, Default, PartialEq)]
|
||||||
#[rmc_struct(0)]
|
#[rmc_struct(0)]
|
||||||
pub struct Gathering {
|
pub struct Gathering {
|
||||||
pub self_gid: u32,
|
pub self_gid: u32,
|
||||||
|
|
@ -21,41 +24,60 @@ pub struct Gathering {
|
||||||
}
|
}
|
||||||
|
|
||||||
// rmc structure
|
// rmc structure
|
||||||
#[derive(RmcSerialize, Debug, Clone, Default)]
|
#[derive(RmcSerialize, Debug, Clone, Default, PartialEq)]
|
||||||
#[rmc_struct(0)]
|
#[rmc_struct(0)]
|
||||||
pub struct MatchmakeParam {
|
pub struct MatchmakeParam {
|
||||||
pub params: Vec<(String, Variant)>,
|
pub params: Vec<(String, Variant)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// rmc structure
|
cfg_if! {
|
||||||
#[derive(RmcSerialize, Debug, Clone, Default)]
|
if #[cfg(feature = "v3-5-0")]{
|
||||||
#[rmc_struct(3)]
|
#[derive(RmcSerialize, Debug, Clone, Default, PartialEq)]
|
||||||
pub struct MatchmakeSession {
|
#[rmc_struct(3)]
|
||||||
//inherits from
|
pub struct MatchmakeSession {
|
||||||
#[extends]
|
//inherits from
|
||||||
pub gathering: Gathering,
|
#[extends]
|
||||||
|
pub gathering: Gathering,
|
||||||
|
|
||||||
pub gamemode: u32,
|
pub gamemode: u32,
|
||||||
pub attributes: Vec<u32>,
|
pub attributes: Vec<u32>,
|
||||||
pub open_participation: bool,
|
pub open_participation: bool,
|
||||||
pub matchmake_system_type: u32,
|
pub matchmake_system_type: u32,
|
||||||
pub application_buffer: Vec<u8>,
|
pub application_buffer: Vec<u8>,
|
||||||
pub participation_count: u32,
|
pub participation_count: u32,
|
||||||
pub progress_score: u8,
|
pub progress_score: u8,
|
||||||
pub session_key: Vec<u8>,
|
pub session_key: Vec<u8>,
|
||||||
pub option0: u32,
|
pub option0: u32,
|
||||||
pub matchmake_param: MatchmakeParam,
|
pub matchmake_param: MatchmakeParam,
|
||||||
pub datetime: KerberosDateTime,
|
pub datetime: KerberosDateTime,
|
||||||
pub user_password: String,
|
pub user_password: String,
|
||||||
pub refer_gid: u32,
|
pub refer_gid: u32,
|
||||||
pub user_password_enabled: bool,
|
pub user_password_enabled: bool,
|
||||||
pub system_password_enabled: bool,
|
pub system_password_enabled: bool,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#[derive(RmcSerialize, Debug, Clone, Default, PartialEq)]
|
||||||
|
#[rmc_struct(0)]
|
||||||
|
pub struct MatchmakeSession {
|
||||||
|
//inherits from
|
||||||
|
#[extends]
|
||||||
|
pub gathering: Gathering,
|
||||||
|
|
||||||
|
pub gamemode: u32,
|
||||||
|
pub attributes: Vec<u32>,
|
||||||
|
pub open_participation: bool,
|
||||||
|
pub matchmake_system_type: u32,
|
||||||
|
pub application_buffer: Vec<u8>,
|
||||||
|
pub participation_count: u32,
|
||||||
|
pub session_key: Vec<u8>,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RmcSerialize, Debug, Clone)]
|
#[derive(RmcSerialize, Debug, Clone)]
|
||||||
#[rmc_struct(3)]
|
#[rmc_struct(3)]
|
||||||
pub struct MatchmakeSessionSearchCriteria {
|
pub struct MatchmakeSessionSearchCriteria {
|
||||||
pub attribs: Vec<String>,
|
pub attribs: Vec<StringSet<u32>>,
|
||||||
pub game_mode: String,
|
pub game_mode: String,
|
||||||
pub minimum_participants: String,
|
pub minimum_participants: String,
|
||||||
pub maximum_participants: String,
|
pub maximum_participants: String,
|
||||||
|
|
@ -101,20 +123,40 @@ pub struct MatchmakeBlockListParam {
|
||||||
option_flag: u32,
|
option_flag: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RmcSerialize, Debug, Clone)]
|
cfg_if! {
|
||||||
#[rmc_struct(0)]
|
if #[cfg(feature = "v3-10-22")] {
|
||||||
pub struct JoinMatchmakeSessionParam {
|
#[derive(RmcSerialize, Debug, Clone)]
|
||||||
pub gid: u32,
|
#[rmc_struct(1)]
|
||||||
pub additional_participants: Vec<PID>,
|
pub struct JoinMatchmakeSessionParam {
|
||||||
pub gid_for_participation_check: u32,
|
pub gid: u32,
|
||||||
pub join_matchmake_session_open: u32,
|
pub additional_participants: Vec<PID>,
|
||||||
pub join_matchmake_session_behavior: u8,
|
pub gid_for_participation_check: u32,
|
||||||
pub user_password: String,
|
pub join_matchmake_session_open: u32,
|
||||||
pub system_password: String,
|
pub join_matchmake_session_behavior: u8,
|
||||||
pub join_message: String,
|
pub user_password: String,
|
||||||
pub participation_count: u16,
|
pub system_password: String,
|
||||||
//pub extra_participant: u16,
|
pub join_message: String,
|
||||||
//pub block_list_param: MatchmakeBlockListParam
|
pub participation_count: u16,
|
||||||
|
pub extra_participant: u16,
|
||||||
|
//pub block_list_param: MatchmakeBlockListParam
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#[derive(RmcSerialize, Debug, Clone)]
|
||||||
|
#[rmc_struct(0)]
|
||||||
|
pub struct JoinMatchmakeSessionParam {
|
||||||
|
pub gid: u32,
|
||||||
|
pub additional_participants: Vec<PID>,
|
||||||
|
pub gid_for_participation_check: u32,
|
||||||
|
pub join_matchmake_session_open: u32,
|
||||||
|
pub join_matchmake_session_behavior: u8,
|
||||||
|
pub user_password: String,
|
||||||
|
pub system_password: String,
|
||||||
|
pub join_message: String,
|
||||||
|
pub participation_count: u16,
|
||||||
|
//pub extra_participant: u16,
|
||||||
|
//pub block_list_param: MatchmakeBlockListParam
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod gathering_flags {
|
pub mod gathering_flags {
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,15 @@ pub enum Error {
|
||||||
Utf8(#[from] FromUtf8Error),
|
Utf8(#[from] FromUtf8Error),
|
||||||
#[error("unexpected value: {0}")]
|
#[error("unexpected value: {0}")]
|
||||||
UnexpectedValue(u64),
|
UnexpectedValue(u64),
|
||||||
|
#[cfg(feature = "rmc_struct_header")]
|
||||||
#[error("version mismatch: {0}")]
|
#[error("version mismatch: {0}")]
|
||||||
VersionMismatch(u8),
|
VersionMismatch(u8),
|
||||||
#[error("an error occurred reading the station url")]
|
#[error("an error occurred reading the station url")]
|
||||||
StationUrlInvalid,
|
StationUrlInvalid,
|
||||||
#[error("error formatting text: {0}")]
|
#[error("error formatting text: {0}")]
|
||||||
FormatError(#[from] fmt::Error),
|
FormatError(#[from] fmt::Error),
|
||||||
|
#[error("uncategorized rmc error occurred: {0}")]
|
||||||
|
Other(Box<dyn std::error::Error + Send + Sync>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
@ -35,10 +38,11 @@ pub mod primitives;
|
||||||
pub mod qbuffer;
|
pub mod qbuffer;
|
||||||
pub mod qresult;
|
pub mod qresult;
|
||||||
pub mod ranking;
|
pub mod ranking;
|
||||||
|
pub mod resultsrange;
|
||||||
pub mod rmc_struct;
|
pub mod rmc_struct;
|
||||||
pub mod string;
|
pub mod string;
|
||||||
|
pub mod string_set;
|
||||||
pub mod variant;
|
pub mod variant;
|
||||||
pub mod resultsrange;
|
|
||||||
|
|
||||||
pub trait RmcSerialize {
|
pub trait RmcSerialize {
|
||||||
fn serialize(&self, writer: &mut impl Write) -> Result<()>;
|
fn serialize(&self, writer: &mut impl Write) -> Result<()>;
|
||||||
|
|
@ -66,6 +70,9 @@ pub trait RmcSerialize {
|
||||||
fn name() -> &'static str {
|
fn name() -> &'static str {
|
||||||
"NoNameSpecified"
|
"NoNameSpecified"
|
||||||
}
|
}
|
||||||
|
fn version() -> Option<u8> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RmcSerialize for () {
|
impl RmcSerialize for () {
|
||||||
|
|
|
||||||
95
rnex-core/src/rmc/structures/string_set.rs
Normal file
95
rnex-core/src/rmc/structures/string_set.rs
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
use std::{collections::HashSet, hash::Hash, str::FromStr, string::ToString};
|
||||||
|
|
||||||
|
use rnex_core::rmc::structures::RmcSerialize;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct StringSet<T: FromStr + ToString + Eq>(pub HashSet<T>)
|
||||||
|
where
|
||||||
|
<T as FromStr>::Err: std::error::Error + Send + Sync + 'static;
|
||||||
|
|
||||||
|
impl<T: FromStr + ToString + Eq + Hash> PartialEq for StringSet<T>
|
||||||
|
where
|
||||||
|
<T as FromStr>::Err: std::error::Error + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.0.iter().eq(&other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: FromStr + ToString + Eq + Hash> ToString for StringSet<T>
|
||||||
|
where
|
||||||
|
<T as FromStr>::Err: std::error::Error + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
self.0
|
||||||
|
.iter()
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.reduce(|a, b| format!("{}|{}", a, b))
|
||||||
|
.unwrap_or(String::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: FromStr + ToString + Eq + Hash> FromStr for StringSet<T>
|
||||||
|
where
|
||||||
|
<T as FromStr>::Err: std::error::Error + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
type Err = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Ok(Self(
|
||||||
|
s.split("|")
|
||||||
|
.filter(|v| !v.is_empty())
|
||||||
|
.map(T::from_str)
|
||||||
|
.try_fold(
|
||||||
|
HashSet::new(),
|
||||||
|
|mut a, b| -> Result<HashSet<T>, Self::Err> {
|
||||||
|
a.insert(b.map_err(Box::new)?);
|
||||||
|
Ok(a)
|
||||||
|
},
|
||||||
|
)?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: FromStr + ToString + Eq + Hash> RmcSerialize for StringSet<T>
|
||||||
|
where
|
||||||
|
<T as FromStr>::Err: std::error::Error + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
fn deserialize(reader: &mut impl std::io::prelude::Read) -> super::Result<Self>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Self::from_str(&String::deserialize(reader)?).map_err(super::Error::Other)
|
||||||
|
}
|
||||||
|
fn serialize(&self, writer: &mut impl std::io::prelude::Write) -> super::Result<()> {
|
||||||
|
self.to_string().serialize(writer)
|
||||||
|
}
|
||||||
|
fn serialize_write_size(&self) -> super::Result<u32> {
|
||||||
|
self.to_string().serialize_write_size()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use crate::rmc::structures::string_set::StringSet;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {
|
||||||
|
let str_val = "0|100|200|10|110|210|20|120|220|30|130|230";
|
||||||
|
let set: StringSet<u32> = StringSet::from_str(str_val).unwrap();
|
||||||
|
let string_2 = set.to_string();
|
||||||
|
let reset: StringSet<u32> = StringSet::from_str(&string_2).unwrap();
|
||||||
|
|
||||||
|
for val in &set.0 {
|
||||||
|
if !reset.0.contains(&val) {
|
||||||
|
panic!("sets arent equivalent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _: StringSet<u32> = StringSet::from_str("").unwrap();
|
||||||
|
|
||||||
|
let _: StringSet<u32> = StringSet::from_str("10").unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,7 @@ use rnex_core::rmc::structures;
|
||||||
use rnex_core::rmc::structures::{Result, RmcSerialize};
|
use rnex_core::rmc::structures::{Result, RmcSerialize};
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default, PartialEq)]
|
||||||
pub enum Variant {
|
pub enum Variant {
|
||||||
#[default]
|
#[default]
|
||||||
None,
|
None,
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ pub struct ConnectionInitData {
|
||||||
mod test {
|
mod test {
|
||||||
use std::{
|
use std::{
|
||||||
io::Cursor,
|
io::Cursor,
|
||||||
net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4},
|
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,25 @@
|
||||||
use std::ops::Deref;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use log::{error, info};
|
|
||||||
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt};
|
|
||||||
use tokio::sync::mpsc::{channel, Receiver, Sender};
|
|
||||||
use tokio::sync::Notify;
|
|
||||||
use tokio::task;
|
|
||||||
use crate::reggie::{UnitPacketRead, UnitPacketWrite};
|
use crate::reggie::{UnitPacketRead, UnitPacketWrite};
|
||||||
|
use log::{error, info};
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::sync::{Arc, Weak};
|
||||||
|
use std::vec;
|
||||||
|
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt};
|
||||||
|
use tokio::sync::Notify;
|
||||||
|
use tokio::sync::mpsc::{Receiver, Sender, channel};
|
||||||
|
use tokio::task;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SendingBufferConnection(Sender<Vec<u8>>, Arc<Notify>);
|
pub struct SendingBufferConnection(Sender<Vec<u8>>, Arc<Notify>);
|
||||||
|
|
||||||
pub struct SplittableBufferConnection(SendingBufferConnection, Receiver<Vec<u8>>);
|
pub struct SplittableBufferConnection(SendingBufferConnection, Receiver<Vec<u8>>);
|
||||||
|
|
||||||
impl AsRef<SendingBufferConnection> for SplittableBufferConnection{
|
impl AsRef<SendingBufferConnection> for SplittableBufferConnection {
|
||||||
fn as_ref(&self) -> &SendingBufferConnection {
|
fn as_ref(&self) -> &SendingBufferConnection {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for SplittableBufferConnection{
|
impl Deref for SplittableBufferConnection {
|
||||||
type Target = SendingBufferConnection;
|
type Target = SendingBufferConnection;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
|
|
@ -26,9 +27,7 @@ impl Deref for SplittableBufferConnection{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Send + Unpin + AsyncWrite + AsyncRead + 'static> From<T> for SplittableBufferConnection {
|
||||||
|
|
||||||
impl<T: Send + Unpin + AsyncWrite + AsyncRead + 'static> From<T> for SplittableBufferConnection{
|
|
||||||
fn from(value: T) -> Self {
|
fn from(value: T) -> Self {
|
||||||
Self::new(value)
|
Self::new(value)
|
||||||
}
|
}
|
||||||
|
|
@ -48,7 +47,6 @@ impl SplittableBufferConnection {
|
||||||
let mut recver = inside_recv;
|
let mut recver = inside_recv;
|
||||||
let mut stream = stream;
|
let mut stream = stream;
|
||||||
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
data = recver.recv() => {
|
data = recver.recv() => {
|
||||||
|
|
@ -81,7 +79,7 @@ impl SplittableBufferConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Err(e) = stream.shutdown().await{
|
if let Err(e) = stream.shutdown().await {
|
||||||
error!("failed to shut down stream: {}", e);
|
error!("failed to shut down stream: {}", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -91,11 +89,11 @@ impl SplittableBufferConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SendingBufferConnection{
|
impl SendingBufferConnection {
|
||||||
pub async fn send(&self, buffer: Vec<u8>) -> Option<()>{
|
pub async fn send(&self, buffer: Vec<u8>) -> Option<()> {
|
||||||
self.0.send(buffer).await.ok()
|
self.0.send(buffer).await.ok()
|
||||||
}
|
}
|
||||||
pub fn is_alive(&self) -> bool{
|
pub fn is_alive(&self) -> bool {
|
||||||
!self.0.is_closed()
|
!self.0.is_closed()
|
||||||
}
|
}
|
||||||
pub async fn disconnect(&self) {
|
pub async fn disconnect(&self) {
|
||||||
|
|
@ -106,12 +104,34 @@ impl SendingBufferConnection{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SplittableBufferConnection{
|
impl SplittableBufferConnection {
|
||||||
pub async fn recv(&mut self) -> Option<Vec<u8>>{
|
pub async fn recv(&mut self) -> Option<Vec<u8>> {
|
||||||
self.1.recv().await
|
self.1.recv().await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn duplicate_sender(&self) -> SendingBufferConnection{
|
pub fn duplicate_sender(&self) -> SendingBufferConnection {
|
||||||
self.0.clone()
|
self.0.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct WeakVec<T>(Vec<Weak<T>>);
|
||||||
|
|
||||||
|
impl<T> WeakVec<T> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(vec![])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_vec(vec: Vec<Weak<T>>) -> Self {
|
||||||
|
Self(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, val: Weak<T>) {
|
||||||
|
self.0.retain(|v| v.upgrade().is_some());
|
||||||
|
|
||||||
|
self.0.push(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> impl Iterator<Item = Arc<T>> {
|
||||||
|
self.0.iter().filter_map(|w| w.upgrade())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,95 +3,93 @@ use std::ops::{BitAnd, BitOr};
|
||||||
use typenum::{Cmp, IsEqual, IsLess, IsLessOrEqual, Unsigned};
|
use typenum::{Cmp, IsEqual, IsLess, IsLessOrEqual, Unsigned};
|
||||||
|
|
||||||
/// This trait represents a version at compile time
|
/// This trait represents a version at compile time
|
||||||
trait Version{
|
trait Version {
|
||||||
type Major: Unsigned;
|
type Major: Unsigned;
|
||||||
type Minor: Unsigned;
|
type Minor: Unsigned;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This struct contains nothing and is used to represent specific versions as an instance of
|
/// This struct contains nothing and is used to represent specific versions as an instance of
|
||||||
/// [`Version`]. It is instances as `Ver<Major, Minor>`
|
/// [`Version`]. It is instances as `Ver<Major, Minor>`
|
||||||
struct Ver<MAJ: Unsigned, MIN: Unsigned>{
|
struct Ver<MAJ: Unsigned, MIN: Unsigned> {
|
||||||
_phantom: PhantomData<(MAJ, MIN)>
|
_phantom: PhantomData<(MAJ, MIN)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<MAJ: Unsigned, MIN: Unsigned> Version for Ver<MAJ, MIN>{
|
impl<MAJ: Unsigned, MIN: Unsigned> Version for Ver<MAJ, MIN> {
|
||||||
type Major = MAJ;
|
type Major = MAJ;
|
||||||
type Minor = MIN;
|
type Minor = MIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents two versions which can be compared
|
/// Represents two versions which can be compared
|
||||||
trait ComparableVersion<T: Version>: Version{
|
trait ComparableVersion<T: Version>: Version {
|
||||||
type IsAtLeast: SameOrUnit;
|
type IsAtLeast: SameOrUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Version, U: Version> ComparableVersion<T> for U where
|
impl<T: Version, U: Version> ComparableVersion<T> for U
|
||||||
|
where
|
||||||
<T as Version>::Major: Cmp<Self::Major>,
|
<T as Version>::Major: Cmp<Self::Major>,
|
||||||
<T as Version>::Minor: IsLessOrEqual<Self::Minor>,
|
<T as Version>::Minor: IsLessOrEqual<Self::Minor>,
|
||||||
<T as Version>::Major: IsEqual<
|
<T as Version>::Major:
|
||||||
Self::Major,
|
IsEqual<Self::Major, Output: BitAnd<typenum::LeEq<T::Minor, Self::Minor>>>,
|
||||||
Output: BitAnd<
|
|
||||||
typenum::LeEq<T::Minor, Self::Minor>
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
<T as Version>::Major: IsLess<
|
<T as Version>::Major: IsLess<
|
||||||
Self::Major,
|
Self::Major,
|
||||||
Output: BitOr<
|
Output: BitOr<
|
||||||
typenum::And<
|
typenum::And<
|
||||||
typenum::Eq<T::Major, Self::Major>,
|
typenum::Eq<T::Major, Self::Major>,
|
||||||
typenum::LeEq<T::Minor, Self::Minor>,
|
typenum::LeEq<T::Minor, Self::Minor>,
|
||||||
|
>,
|
||||||
|
Output: SameOrUnit,
|
||||||
>,
|
>,
|
||||||
Output: SameOrUnit
|
>,
|
||||||
>
|
{
|
||||||
> {
|
|
||||||
|
|
||||||
type IsAtLeast = typenum::Or<
|
type IsAtLeast = typenum::Or<
|
||||||
typenum::Le<T::Major, Self::Major>,
|
typenum::Le<T::Major, Self::Major>,
|
||||||
typenum::And<
|
typenum::And<typenum::Eq<T::Major, Self::Major>, typenum::LeEq<T::Minor, Self::Minor>>,
|
||||||
typenum::Eq<T::Major, Self::Major>,
|
|
||||||
typenum::LeEq<T::Minor, Self::Minor>,
|
|
||||||
>
|
|
||||||
>;
|
>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Simple check for testing if the `TEST` version is at least `REQ` or higher.
|
/// Simple check for testing if the `TEST` version is at least `REQ` or higher.
|
||||||
type VersionAbove<REQ, TEST> = <TEST as ComparableVersion<REQ>>::IsAtLeast;
|
type VersionAbove<REQ, TEST> = <TEST as ComparableVersion<REQ>>::IsAtLeast;
|
||||||
|
|
||||||
trait VersionIsAtLeast<VER: Version>{}
|
trait VersionIsAtLeast<VER: Version> {}
|
||||||
|
|
||||||
impl<VER: Version, T: ComparableVersion<VER, IsAtLeast = typenum::True>> VersionIsAtLeast<VER> for T{}
|
|
||||||
|
|
||||||
|
impl<VER: Version, T: ComparableVersion<VER, IsAtLeast = typenum::True>> VersionIsAtLeast<VER>
|
||||||
|
for T
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// Trait for containing the result of elements which only conditionally exist
|
/// Trait for containing the result of elements which only conditionally exist
|
||||||
trait CondElemResult{
|
trait CondElemResult {
|
||||||
type Output;
|
type Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Empty helper struct which only servers to give a concrete type when creating fields in rmc
|
/// Empty helper struct which only servers to give a concrete type when creating fields in rmc
|
||||||
/// structs which have a version requirement. This is not meant to be used directly, use
|
/// structs which have a version requirement. This is not meant to be used directly, use
|
||||||
/// [`MinVersion`] instead.
|
/// [`MinVersion`] instead.
|
||||||
struct MinVersionElementHelper<T, REQUIRED: Version, VER: Version + ComparableVersion<REQUIRED>>{
|
struct MinVersionElementHelper<T, REQUIRED: Version, VER: Version + ComparableVersion<REQUIRED>> {
|
||||||
_phantom: PhantomData<(T, REQUIRED, VER)>
|
_phantom: PhantomData<(T, REQUIRED, VER)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This should be used either with [`typenum::True`] or [`typenum::False`]. When `True` the [`Self::Output`]
|
/// This should be used either with [`typenum::True`] or [`typenum::False`]. When `True` the [`Self::Output`]
|
||||||
/// will be the same as the `T` you put into Output. When `False` it will always be `()`
|
/// will be the same as the `T` you put into Output. When `False` it will always be `()`
|
||||||
trait SameOrUnit{
|
trait SameOrUnit {
|
||||||
type Output<T>;
|
type Output<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SameOrUnit for typenum::True{
|
impl SameOrUnit for typenum::True {
|
||||||
type Output<T> = T;
|
type Output<T> = T;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SameOrUnit for typenum::False{
|
impl SameOrUnit for typenum::False {
|
||||||
type Output<T> = ();
|
type Output<T> = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, REQUIRED: Version, VER: Version + ComparableVersion<REQUIRED>> CondElemResult for MinVersionElementHelper<T, REQUIRED, VER> where {
|
impl<T, REQUIRED: Version, VER: Version + ComparableVersion<REQUIRED>> CondElemResult
|
||||||
|
for MinVersionElementHelper<T, REQUIRED, VER>
|
||||||
|
{
|
||||||
type Output = <<VER as ComparableVersion<REQUIRED>>::IsAtLeast as SameOrUnit>::Output<T>;
|
type Output = <<VER as ComparableVersion<REQUIRED>>::IsAtLeast as SameOrUnit>::Output<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When the version condition is met the field will exist and will simply be `T` if not it will be
|
/// When the version condition is met the field will exist and will simply be `T` if not it will be
|
||||||
/// replaced by `()`. Use this when you need to add versioning to rmc structs.
|
/// replaced by `()`. Use this when you need to add versioning to rmc structs.
|
||||||
type MinVersion<T, REQUIRED, VER> = <MinVersionElementHelper<T, REQUIRED, VER> as CondElemResult>::Output;
|
type MinVersion<T, REQUIRED, VER> =
|
||||||
|
<MinVersionElementHelper<T, REQUIRED, VER> as CondElemResult>::Output;
|
||||||
|
|
|
||||||
3
setup-hook.sh
Executable file
3
setup-hook.sh
Executable file
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
cp buildscripts/pre-commit .git/hooks/
|
||||||
13
test-all.sh
Executable file
13
test-all.sh
Executable file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
EDITIONS=$(yq ea "." editions.yaml | yq 'keys[]')
|
||||||
|
IFS=$'\n'
|
||||||
|
while IFS=$'\n' read -r EDITION; do
|
||||||
|
if [[ $(yq ea ".$EDITION.include-in-checkall" editions.yaml) == "true" ]]
|
||||||
|
then
|
||||||
|
export EDITION
|
||||||
|
./test-edition.sh $EDITION
|
||||||
|
fi
|
||||||
|
done <<< "$EDITIONS"
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
if [ -z ${EDITION+x} ]; then
|
if [ -z ${EDITION+x} ]; then
|
||||||
EDITION=$1
|
EDITION=$1
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue