refactor: re-organize workspace (#101)

- Remove Tauri client.

  It was useful when initially prototyping the Web Component, but now
  it’s more of a maintenance burden. It’s notably not convenient to
  check in CI. Since we now have another native alternative that does
  not require any GPU (`ironrdp-client`), it’s probably a good time to
  part ways.

- Move wasm package into the workspace.

- Move Rust crates into a `crates` subfolder.

- Introduce `xtask` crate for free-form automation.
This commit is contained in:
Benoît Cortier 2023-03-29 19:09:15 -04:00 committed by GitHub
parent 4ad13df499
commit 710a51f24a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
378 changed files with 1424 additions and 1814 deletions

2
.cargo/config.toml Normal file
View file

@ -0,0 +1,2 @@
[alias]
xtask = "run --package xtask --"

View file

@ -28,7 +28,7 @@ jobs:
if ($LastExitCode -eq 1) { if ($LastExitCode -eq 1) {
throw "Bad formatting, please run 'cargo +stable fmt --all'" throw "Bad formatting, please run 'cargo +stable fmt --all'"
} }
lints: lints:
name: Lints name: Lints
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
@ -47,7 +47,8 @@ jobs:
key: ${{ runner.os }}-lints-${{ hashFiles('Cargo.lock') }} key: ${{ runner.os }}-lints-${{ hashFiles('Cargo.lock') }}
- name: Check clippy - name: Check clippy
run: cargo clippy --workspace -- -D warnings # FIXME: run: cargo clippy --workspace -- -D warnings
run: cargo clippy -- -D warnings
wasm: wasm:
name: WASM target name: WASM target
@ -63,15 +64,14 @@ jobs:
path: | path: |
~/.cargo/registry/ ~/.cargo/registry/
~/.cargo/git/ ~/.cargo/git/
./ffi/wasm/target/ ./target/
key: ${{ runner.os }}-wasm-${{ hashFiles('ffi/wasm/Cargo.lock') }} key: ${{ runner.os }}-wasm-${{ hashFiles('ffi/wasm/Cargo.lock') }}
- name: Prepare runner - name: Prepare runner
run: sudo apt install wabt run: sudo apt install wabt
- name: Check - name: Check
shell: pwsh run: cargo xtask check wasm
run: ./ffi/wasm/check.ps1
tests: tests:
name: Tests [${{ matrix.os }}] name: Tests [${{ matrix.os }}]
@ -100,7 +100,8 @@ jobs:
key: ${{ runner.os }}-tests-${{ hashFiles('Cargo.lock') }} key: ${{ runner.os }}-tests-${{ hashFiles('Cargo.lock') }}
- name: Test [${{ matrix.os }}] - name: Test [${{ matrix.os }}]
run: cargo test --workspace # FIXME: run: cargo test --workspace
run: cargo test
fuzz: fuzz:
name: Fuzzing name: Fuzzing

6
.gitignore vendored
View file

@ -1,6 +1,12 @@
# Build artifacts
/target /target
# Log files
*.log *.log
# Coverage
/docs
# Editor/IDE files # Editor/IDE files
*~ *~
/tags /tags

486
Cargo.lock generated
View file

@ -114,8 +114,8 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
"synstructure", "synstructure",
] ]
@ -126,8 +126,8 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -440,8 +440,8 @@ checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro-error", "proc-macro-error",
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -504,6 +504,26 @@ dependencies = [
"unicode-width", "unicode-width",
] ]
[[package]]
name = "console_error_panic_hook"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
dependencies = [
"cfg-if 1.0.0",
"wasm-bindgen",
]
[[package]]
name = "console_log"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f"
dependencies = [
"log",
"web-sys",
]
[[package]] [[package]]
name = "const-oid" name = "const-oid"
version = "0.7.1" version = "0.7.1"
@ -690,7 +710,7 @@ version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
dependencies = [ dependencies = [
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -721,8 +741,8 @@ dependencies = [
"cc", "cc",
"codespan-reporting", "codespan-reporting",
"once_cell", "once_cell",
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"scratch", "scratch",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -739,8 +759,8 @@ version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470" checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -762,8 +782,8 @@ checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
dependencies = [ dependencies = [
"fnv", "fnv",
"ident_case", "ident_case",
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"strsim", "strsim",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -775,7 +795,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -839,8 +859,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ef71ddb5b3a1f53dee24817c8f70dfa1cb29e804c18d88c228d4bc9c86ee3b9" checksum = "8ef71ddb5b3a1f53dee24817c8f70dfa1cb29e804c18d88c228d4bc9c86ee3b9"
dependencies = [ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -850,8 +870,8 @@ version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -911,8 +931,8 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -1068,8 +1088,8 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8469d0d40519bc608ec6863f1cc88f3f1deee15913f2f3b3e573d81ed38cccc" checksum = "c8469d0d40519bc608ec6863f1cc88f3f1deee15913f2f3b3e573d81ed38cccc"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -1139,9 +1159,9 @@ dependencies = [
[[package]] [[package]]
name = "futures-channel" name = "futures-channel"
version = "0.3.25" version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
@ -1149,9 +1169,9 @@ dependencies = [
[[package]] [[package]]
name = "futures-core" name = "futures-core"
version = "0.3.25" version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd"
[[package]] [[package]]
name = "futures-executor" name = "futures-executor"
@ -1166,32 +1186,32 @@ dependencies = [
[[package]] [[package]]
name = "futures-io" name = "futures-io"
version = "0.3.25" version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91"
[[package]] [[package]]
name = "futures-macro" name = "futures-macro"
version = "0.3.25" version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
] ]
[[package]] [[package]]
name = "futures-sink" name = "futures-sink"
version = "0.3.25" version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2"
[[package]] [[package]]
name = "futures-task" name = "futures-task"
version = "0.3.25" version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879"
[[package]] [[package]]
name = "futures-timer" name = "futures-timer"
@ -1201,9 +1221,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
[[package]] [[package]]
name = "futures-util" name = "futures-util"
version = "0.3.25" version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
@ -1264,8 +1284,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"js-sys",
"libc", "libc",
"wasi 0.11.0+wasi-snapshot-preview1", "wasi 0.11.0+wasi-snapshot-preview1",
"wasm-bindgen",
] ]
[[package]] [[package]]
@ -1279,6 +1301,39 @@ dependencies = [
"xml-rs", "xml-rs",
] ]
[[package]]
name = "gloo-net"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9902a044653b26b99f7e3693a42f171312d9be8b26b5697bd1e43ad1f8a35e10"
dependencies = [
"futures-channel",
"futures-core",
"futures-sink",
"gloo-utils",
"js-sys",
"pin-project",
"serde",
"serde_json",
"thiserror",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "gloo-utils"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8e8fc851e9c7b9852508bc6e3f690f452f474417e8545ec9857b7f7377036b5"
dependencies = [
"js-sys",
"serde",
"serde_json",
"wasm-bindgen",
"web-sys",
]
[[package]] [[package]]
name = "glow" name = "glow"
version = "0.11.2" version = "0.11.2"
@ -1623,11 +1678,11 @@ checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745"
[[package]] [[package]]
name = "ironrdp" name = "ironrdp"
version = "0.4.2" version = "0.5.0"
dependencies = [ dependencies = [
"ironrdp-core",
"ironrdp-graphics", "ironrdp-graphics",
"ironrdp-input", "ironrdp-input",
"ironrdp-pdu",
"ironrdp-session", "ironrdp-session",
] ]
@ -1645,6 +1700,7 @@ dependencies = [
"inquire", "inquire",
"ironrdp", "ironrdp",
"ironrdp-input", "ironrdp-input",
"ironrdp-session",
"log", "log",
"smallvec", "smallvec",
"softbuffer", "softbuffer",
@ -1660,7 +1716,73 @@ dependencies = [
] ]
[[package]] [[package]]
name = "ironrdp-core" name = "ironrdp-client-glutin"
version = "0.4.2"
dependencies = [
"async-native-tls",
"chrono",
"clap",
"exitcode",
"fern",
"futures-util",
"glutin",
"ironrdp",
"ironrdp-glutin-renderer",
"ironrdp-session",
"log",
"sspi",
"tokio",
"tokio-rustls",
"tokio-util",
"x509-parser 0.14.0",
]
[[package]]
name = "ironrdp-glutin-renderer"
version = "0.1.0"
dependencies = [
"glow",
"glutin",
"ironrdp",
"log",
"openh264",
"thiserror",
]
[[package]]
name = "ironrdp-graphics"
version = "0.1.0"
dependencies = [
"bit_field",
"bitflags",
"bitvec",
"byteorder",
"bytes",
"hex-literal",
"ironrdp-pdu",
"lazy_static",
"num-derive 0.3.3",
"num-traits",
"proptest",
"rdp-rs",
"rstest 0.16.0",
"thiserror",
]
[[package]]
name = "ironrdp-input"
version = "0.1.0"
dependencies = [
"anyhow",
"bitvec",
"ironrdp-pdu",
"proptest",
"rstest 0.16.0",
"smallvec",
]
[[package]]
name = "ironrdp-pdu"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bit_field", "bit_field",
@ -1680,56 +1802,11 @@ dependencies = [
] ]
[[package]] [[package]]
name = "ironrdp-graphics" name = "ironrdp-pdu-generators"
version = "0.1.0" version = "0.0.0"
dependencies = [ dependencies = [
"bit_field", "ironrdp-pdu",
"bitflags",
"bitvec",
"byteorder",
"bytes",
"hex-literal",
"ironrdp-core",
"lazy_static",
"num-derive 0.3.3",
"num-traits",
"proptest", "proptest",
"rdp-rs",
"rstest 0.16.0",
"thiserror",
]
[[package]]
name = "ironrdp-gui-client"
version = "0.4.2"
dependencies = [
"async-native-tls",
"chrono",
"clap",
"exitcode",
"fern",
"futures-util",
"glutin",
"ironrdp",
"ironrdp-renderer",
"log",
"sspi",
"tokio",
"tokio-rustls",
"tokio-util",
"x509-parser 0.14.0",
]
[[package]]
name = "ironrdp-input"
version = "0.1.0"
dependencies = [
"anyhow",
"bitvec",
"ironrdp-core",
"proptest",
"rstest 0.16.0",
"smallvec",
] ]
[[package]] [[package]]
@ -1743,18 +1820,6 @@ dependencies = [
"rstest 0.15.0", "rstest 0.15.0",
] ]
[[package]]
name = "ironrdp-renderer"
version = "0.1.0"
dependencies = [
"glow",
"glutin",
"ironrdp",
"log",
"openh264",
"thiserror",
]
[[package]] [[package]]
name = "ironrdp-replay-client" name = "ironrdp-replay-client"
version = "0.4.2" version = "0.4.2"
@ -1762,7 +1827,7 @@ dependencies = [
"clap", "clap",
"glutin", "glutin",
"ironrdp", "ironrdp",
"ironrdp-renderer", "ironrdp-glutin-renderer",
"log", "log",
"simplelog", "simplelog",
] ]
@ -1777,8 +1842,8 @@ dependencies = [
"byteorder", "byteorder",
"bytes", "bytes",
"futures-util", "futures-util",
"ironrdp-core",
"ironrdp-graphics", "ironrdp-graphics",
"ironrdp-pdu",
"ironrdp-rdcleanpath", "ironrdp-rdcleanpath",
"lazy_static", "lazy_static",
"log", "log",
@ -1801,15 +1866,48 @@ dependencies = [
"byteorder", "byteorder",
"bytes", "bytes",
"futures-util", "futures-util",
"ironrdp-core", "ironrdp-pdu",
"ironrdp-graphics", "ironrdp-session",
"num-traits", "num-traits",
"tokio",
"tokio-util",
]
[[package]]
name = "ironrdp-session-generators"
version = "0.0.0"
dependencies = [
"ironrdp-pdu-generators",
"ironrdp-session",
"proptest",
] ]
[[package]] [[package]]
name = "ironrdp-tls" name = "ironrdp-tls"
version = "0.1.0" version = "0.1.0"
[[package]]
name = "ironrdp-web"
version = "0.1.0"
dependencies = [
"anyhow",
"chrono",
"console_error_panic_hook",
"console_log",
"futures-channel",
"futures-util",
"getrandom 0.2.8",
"gloo-net",
"ironrdp",
"ironrdp-session",
"js-sys",
"log",
"smallvec",
"sspi",
"wasm-bindgen",
"wasm-bindgen-futures",
]
[[package]] [[package]]
name = "is-terminal" name = "is-terminal"
version = "0.4.0" version = "0.4.0"
@ -1891,9 +1989,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.137" version = "0.2.140"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
[[package]] [[package]]
name = "libloading" name = "libloading"
@ -2151,8 +2249,8 @@ checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c"
dependencies = [ dependencies = [
"darling", "darling",
"proc-macro-crate 1.2.1", "proc-macro-crate 1.2.1",
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -2301,8 +2399,8 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -2373,8 +2471,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffa5a33ddddfee04c0283a7653987d634e880347e96b5b2ed64de07efb59db9d" checksum = "ffa5a33ddddfee04c0283a7653987d634e880347e96b5b2ed64de07efb59db9d"
dependencies = [ dependencies = [
"proc-macro-crate 0.1.5", "proc-macro-crate 0.1.5",
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -2385,8 +2483,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce"
dependencies = [ dependencies = [
"proc-macro-crate 1.2.1", "proc-macro-crate 1.2.1",
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -2511,8 +2609,8 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -2736,6 +2834,32 @@ dependencies = [
"uuid", "uuid",
] ]
[[package]]
name = "pico-args"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
[[package]]
name = "pin-project"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55"
dependencies = [
"proc-macro2 1.0.54",
"quote 1.0.26",
"syn 1.0.104",
]
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.9" version = "0.2.9"
@ -2842,8 +2966,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [ dependencies = [
"proc-macro-error-attr", "proc-macro-error-attr",
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
"version_check", "version_check",
] ]
@ -2854,8 +2978,8 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"version_check", "version_check",
] ]
@ -2870,9 +2994,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.47" version = "1.0.54"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -2930,11 +3054,11 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.21" version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
] ]
[[package]] [[package]]
@ -3217,8 +3341,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5015e68a0685a95ade3eee617ff7101ab6a3fc689203101ca16ebc16f2b89c66" checksum = "5015e68a0685a95ade3eee617ff7101ab6a3fc689203101ca16ebc16f2b89c66"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"rustc_version", "rustc_version",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -3230,8 +3354,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7229b505ae0706e64f37ffc54a9c163e11022a6636d58fe1f3f52018257ff9f7" checksum = "7229b505ae0706e64f37ffc54a9c163e11022a6636d58fe1f3f52018257ff9f7"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"rustc_version", "rustc_version",
"syn 1.0.104", "syn 1.0.104",
"unicode-ident", "unicode-ident",
@ -3463,8 +3587,8 @@ version = "1.0.154"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fc80d722935453bcafdc2c9a73cd6fac4dc1938f0346035d84bf99fa9e33217" checksum = "4fc80d722935453bcafdc2c9a73cd6fac4dc1938f0346035d84bf99fa9e33217"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -3673,9 +3797,9 @@ dependencies = [
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.4.7" version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
dependencies = [ dependencies = [
"libc", "libc",
"winapi", "winapi",
@ -3825,8 +3949,19 @@ version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ae548ec36cf198c0ef7710d3c230987c2d6d7bd98ad6edc0274462724c585ce" checksum = "4ae548ec36cf198c0ef7710d3c230987c2d6d7bd98ad6edc0274462724c585ce"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21e3787bb71465627110e7d87ed4faaa36c1f61042ee67badb9e2ef173accc40"
dependencies = [
"proc-macro2 1.0.54",
"quote 1.0.26",
"unicode-ident", "unicode-ident",
] ]
@ -3836,8 +3971,8 @@ version = "0.12.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
"unicode-xid 0.2.4", "unicode-xid 0.2.4",
] ]
@ -3886,8 +4021,8 @@ version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -4008,14 +4143,13 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.22.0" version = "1.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3" checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"bytes", "bytes",
"libc", "libc",
"memchr",
"mio", "mio",
"num_cpus", "num_cpus",
"parking_lot", "parking_lot",
@ -4023,18 +4157,18 @@ dependencies = [
"signal-hook-registry", "signal-hook-registry",
"socket2", "socket2",
"tokio-macros", "tokio-macros",
"winapi", "windows-sys 0.45.0",
] ]
[[package]] [[package]]
name = "tokio-macros" name = "tokio-macros"
version = "1.8.0" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 2.0.11",
] ]
[[package]] [[package]]
@ -4050,9 +4184,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio-util" name = "tokio-util"
version = "0.7.4" version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-core", "futures-core",
@ -4096,8 +4230,8 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
] ]
@ -4327,8 +4461,8 @@ dependencies = [
"bumpalo", "bumpalo",
"log", "log",
"once_cell", "once_cell",
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -4351,7 +4485,7 @@ version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
dependencies = [ dependencies = [
"quote 1.0.21", "quote 1.0.26",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
] ]
@ -4361,8 +4495,8 @@ version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
@ -4468,8 +4602,8 @@ version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"xml-rs", "xml-rs",
] ]
@ -4479,9 +4613,9 @@ version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4834c14b3edf1d9986c83ca79b1e7e3afbe9874c7c144702f6467063259ce45d" checksum = "4834c14b3edf1d9986c83ca79b1e7e3afbe9874c7c144702f6467063259ce45d"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quick-xml", "quick-xml",
"quote 1.0.21", "quote 1.0.26",
] ]
[[package]] [[package]]
@ -4950,6 +5084,30 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
[[package]]
name = "xshell"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "962c039b3a7b16cf4e9a4248397c6585c07547412e7d6a6e035389a802dcfe90"
dependencies = [
"xshell-macros",
]
[[package]]
name = "xshell-macros"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dbabb1cbd15a1d6d12d9ed6b35cc6777d4af87ab3ba155ea37215f20beab80c"
[[package]]
name = "xtask"
version = "0.0.0"
dependencies = [
"anyhow",
"pico-args",
"xshell",
]
[[package]] [[package]]
name = "yansi" name = "yansi"
version = "0.5.1" version = "0.5.1"
@ -4977,8 +5135,8 @@ version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c"
dependencies = [ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.54",
"quote 1.0.21", "quote 1.0.26",
"syn 1.0.104", "syn 1.0.104",
"synstructure", "synstructure",
] ]

View file

@ -1,15 +1,43 @@
[package]
name = "ironrdp"
version = "0.5.0"
edition = "2021"
readme = "README.md"
license = "MIT/Apache-2.0"
homepage = "https://github.com/Devolutions/IronRDP"
repository = "https://github.com/Devolutions/IronRDP"
authors = ["Devolutions Inc. <infos@devolutions.net>"]
description = "A Rust implementation of the Microsoft Remote Desktop Protocol (RDP)"
keywords = ["rdp", "remote", "desktop", "protocol"]
[workspace] [workspace]
members = [ members = [
"ironrdp", "crates/*",
"ironrdp-core", "xtask",
"ironrdp-graphics",
"ironrdp-input",
"ironrdp-session",
"ironrdp-session-async",
"ironrdp-tls",
"ironrdp-rdcleanpath",
"ironrdp-renderer",
"ironrdp-client",
"ironrdp-client-glutin",
"ironrdp-replay-client",
] ]
default-members = [
"crates/pdu",
"crates/session",
"crates/graphics",
"crates/input",
"crates/session-async",
"crates/client",
]
[profile.production]
inherits = "release"
lto = true
[profile.production-wasm]
inherits = "release"
opt-level = "s"
lto = true
[features]
default = []
[dependencies]
ironrdp-pdu = { path = "crates/pdu" }
ironrdp-session = { path = "crates/session" }
ironrdp-graphics = { path = "crates/graphics" }
ironrdp-input = { path = "crates/input" }

View file

@ -1,25 +1,10 @@
# IronRDP # IronRDP
A Rust implementation of the Microsoft Remote Desktop Protocol, with a focus on security. A collection of Rust crates providing an implementation of the Microsoft Remote Desktop Protocol, with a focus on security.
## Architecture (Work In Progress…) ## Demonstration
- `ironrdp`: meta crate re-exporting important crates https://user-images.githubusercontent.com/3809077/202049929-76f42471-aeb0-41da-9118-0dc6ea491bd2.mp4
- `ironrdp-core`: core, RDP protocol packets encoding and decoding.
- `ironrdp-graphics`: image processing primitives and algorithms (ZGFX, DWT…).
- `ironrdp-input`: helpers to build FastPathInput packets.
- `ironrdp-session`: abstract state machine on top of `ironrdp-graphics`.
- `ironrdp-session-async`: `Future`s built on top of `ironrdp-session`.
- `ironrdp-tls`: TLS boilerplate common with most IronRDP clients.
- `ironrdp-devolutions-gateway`: Devolutions Gateway extensions.
- `ironrdp-renderer`: `glutin` primitives for OpenGL rendering.
- `ironrdp-client`: Portable RDP client without GPU acceleration using softbuffer and winit for windowing.
- `ironrdp-client-glutin`: GPU-accelerated RDP client using glutin.
- `ironrdp-replay-client`: utility tool to replay RDP graphics pipeline for debugging purposes.
- `iron-remote-gui`: core frontend ui used by both, iron-svelte-client and iron-tauri-client.
- `iron-svelte-client`: web-based frontend using `Svelte` and `Material` frameworks).
- `iron-tauri-client`: a native client built with Tauri. Frontend is using the `iron-web-client`/`iron-svelte-client` component.
- `ffi/wasm`: WebAssembly high-level bindings targeting web browsers.
## Video Codec Support ## Video Codec Support
@ -50,7 +35,39 @@ Alternatively, you may change a few group policies using `gpedit.msc`:
5. Reboot. 5. Reboot.
## Demonstration ## Architecture (Work In Progress…)
https://user-images.githubusercontent.com/3809077/202049929-76f42471-aeb0-41da-9118-0dc6ea491bd2.mp4 - `ironrdp` (root package): meta crate re-exporting important crates,
- `ironrdp-pdu` (`crates/pdu`): PDU encoding and decoding (no I/O, trivial to fuzz),
- `ironrdp-graphics` (`crates/graphics`): image processing primitives (no I/O, trivial to fuzz),
- `ironrdp-session` (`crates/session`): state machine to drive a complete VNC session (no I/O, not _too_ hard to fuzz),
- `ironrdp-input` (`crates/input`): utilities to manage and build input packets (no I/O),
- `ironrdp-session-async` (`crates/session-async`): provides `Future`s wrapping the session state machine conveniently,
- `ironrdp-tls` (`crates/tls`): TLS boilerplate common with most IronRDP clients,
- `ironrdp-rdcleanpath` (`crates/rdcleanpath`): RDCleanPath PDU structure used by IronRDP web client and Devolutions Gateway,
- `ironrdp-client` (`crates/client`): Portable RDP client without GPU acceleration using softbuffer and winit for windowing,
- `ironrdp-web` (`crates/web`): WebAssembly high-level bindings targeting web browsers,
- `ironrdp-glutin-renderer` (`crates/glutin-renderer`): `glutin` primitives for OpenGL rendering,
- `ironrdp-client-glutin` (`crates/client-glutin`): GPU-accelerated RDP client using glutin,
- `ironrdp-replay-client` (`crates/replay-client`): utility tool to replay RDP graphics pipeline for debugging purposes,
- `ironrdp-pdu-generators` (`crates/pdu-generators`): `proptest` generators for `ironrdp-pdu` types,
- `ironrdp-session-generators` (`crates/session-generators`): `proptest` generators for `ironrdp-session` types,
- `iron-remote-gui` (`web-client/iron-remote-gui`): core frontend UI used by `iron-svelte-client` as a Web Component,
- `iron-svelte-client` (`web-client/iron-svelte-client`): web-based frontend using `Svelte` and `Material` frameworks,
- and finally, `ironrdp-fuzz` (`fuzz`): fuzz targets for core crates.
## General design
- Avoid I/O wherever possible
- Dependency injection when runtime information is necessary in core crates (no system call such as `gethostname`)
- Keep non-portable code out of core crates
- Make crate `no_std`-compatible wherever possible
- Facilitate fuzzing
- In libraries, provide concrete error types either hand-crafted or using `thiserror` crate
- In binaries, use the convenient catch-all error type `anyhow::Error`
- Free-form automation a-la `make` following [`cargo xtask`](https://github.com/matklad/cargo-xtask) specification
## Continuous integration
We use GitHub action and our workflows simply run `cargo xtask`.
The expectation is that, if `cargo xtask ci` passes locally, the CI will be green as well.

View file

@ -1,5 +1,5 @@
[package] [package]
name = "ironrdp-gui-client" name = "ironrdp-client-glutin"
version = "0.4.2" version = "0.4.2"
edition = "2021" edition = "2021"
readme = "README.md" readme = "README.md"
@ -11,13 +11,14 @@ keywords = ["rdp", "client", "remote", "desktop", "protocol", "gfx", "rfx"]
[features] [features]
default = ["rustls"] default = ["rustls"]
rustls = ["dep:tokio-rustls", "ironrdp/rustls"] rustls = ["dep:tokio-rustls", "ironrdp-session/rustls"]
native-tls = ["dep:async-native-tls", "ironrdp/native-tls"] native-tls = ["dep:async-native-tls", "ironrdp-session/native-tls"]
[dependencies] [dependencies]
# Protocol # Protocols
ironrdp = { path = "../ironrdp" } ironrdp = { path = "../.." }
ironrdp-session = { path = "../session" }
sspi = { version = "0.8", features = ["network_client"] } sspi = { version = "0.8", features = ["network_client"] }
# CLI # CLI
@ -43,4 +44,4 @@ chrono = "0.4.23"
# GUI # GUI
glutin = "0.29" glutin = "0.29"
ironrdp-renderer = { path = "../ironrdp-renderer"} ironrdp-glutin-renderer = { path = "../glutin-renderer"}

View file

@ -26,11 +26,11 @@ enum SecurityProtocol {
} }
impl SecurityProtocol { impl SecurityProtocol {
fn parse(security_protocol: SecurityProtocol) -> ironrdp::core::SecurityProtocol { fn parse(security_protocol: SecurityProtocol) -> ironrdp::pdu::SecurityProtocol {
match security_protocol { match security_protocol {
SecurityProtocol::Ssl => ironrdp::core::SecurityProtocol::SSL, SecurityProtocol::Ssl => ironrdp::pdu::SecurityProtocol::SSL,
SecurityProtocol::Hybrid => ironrdp::core::SecurityProtocol::HYBRID, SecurityProtocol::Hybrid => ironrdp::pdu::SecurityProtocol::HYBRID,
SecurityProtocol::HybridEx => ironrdp::core::SecurityProtocol::HYBRID_EX, SecurityProtocol::HybridEx => ironrdp::pdu::SecurityProtocol::HYBRID_EX,
} }
} }
} }
@ -47,15 +47,15 @@ enum KeyboardType {
} }
impl KeyboardType { impl KeyboardType {
fn parse(keyboard_type: KeyboardType) -> ironrdp::gcc::KeyboardType { fn parse(keyboard_type: KeyboardType) -> ironrdp::pdu::gcc::KeyboardType {
match keyboard_type { match keyboard_type {
KeyboardType::IbmEnhanced => ironrdp::gcc::KeyboardType::IbmEnhanced, KeyboardType::IbmEnhanced => ironrdp::pdu::gcc::KeyboardType::IbmEnhanced,
KeyboardType::IbmPcAt => ironrdp::gcc::KeyboardType::IbmPcAt, KeyboardType::IbmPcAt => ironrdp::pdu::gcc::KeyboardType::IbmPcAt,
KeyboardType::IbmPcXt => ironrdp::gcc::KeyboardType::IbmPcXt, KeyboardType::IbmPcXt => ironrdp::pdu::gcc::KeyboardType::IbmPcXt,
KeyboardType::OlivettiIco => ironrdp::gcc::KeyboardType::OlivettiIco, KeyboardType::OlivettiIco => ironrdp::pdu::gcc::KeyboardType::OlivettiIco,
KeyboardType::Nokia1050 => ironrdp::gcc::KeyboardType::Nokia1050, KeyboardType::Nokia1050 => ironrdp::pdu::gcc::KeyboardType::Nokia1050,
KeyboardType::Nokia9140 => ironrdp::gcc::KeyboardType::Nokia9140, KeyboardType::Nokia9140 => ironrdp::pdu::gcc::KeyboardType::Nokia9140,
KeyboardType::Japanese => ironrdp::gcc::KeyboardType::Japanese, KeyboardType::Japanese => ironrdp::pdu::gcc::KeyboardType::Japanese,
} }
} }
} }

View file

@ -6,9 +6,9 @@ use std::sync::{self, Arc};
use glutin::dpi::PhysicalPosition; use glutin::dpi::PhysicalPosition;
use glutin::event::{Event, WindowEvent}; use glutin::event::{Event, WindowEvent};
use glutin::event_loop::ControlFlow; use glutin::event_loop::ControlFlow;
use ironrdp::dvc::gfx::ServerPdu; use ironrdp::pdu::dvc::gfx::ServerPdu;
use ironrdp::session::{ErasedWriter, GfxHandler}; use ironrdp::session::{ErasedWriter, GfxHandler};
use ironrdp_renderer::renderer::Renderer; use ironrdp_glutin_renderer::renderer::Renderer;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use self::input::{handle_input_events, translate_input_event}; use self::input::{handle_input_events, translate_input_event};
@ -28,7 +28,7 @@ impl MessagePassingGfxHandler {
} }
impl GfxHandler for MessagePassingGfxHandler { impl GfxHandler for MessagePassingGfxHandler {
fn on_message(&self, message: ServerPdu) -> Result<Option<ironrdp::dvc::gfx::ClientPdu>, RdpError> { fn on_message(&self, message: ServerPdu) -> Result<Option<ironrdp::pdu::dvc::gfx::ClientPdu>, RdpError> {
self.channel.send(message).map_err(|e| RdpError::Send(e.to_string()))?; self.channel.send(message).map_err(|e| RdpError::Send(e.to_string()))?;
Ok(None) Ok(None)
} }

View file

@ -4,10 +4,10 @@ use std::sync::Arc;
use futures_util::AsyncWriteExt; use futures_util::AsyncWriteExt;
use glutin::dpi::PhysicalPosition; use glutin::dpi::PhysicalPosition;
use glutin::event::{ElementState, Event, WindowEvent}; use glutin::event::{ElementState, Event, WindowEvent};
use ironrdp::core::input::fast_path::{FastPathInput, FastPathInputEvent, KeyboardFlags}; use ironrdp::pdu::input::fast_path::{FastPathInput, FastPathInputEvent, KeyboardFlags};
use ironrdp::core::input::mouse::PointerFlags; use ironrdp::pdu::input::mouse::PointerFlags;
use ironrdp::core::input::MousePdu; use ironrdp::pdu::input::MousePdu;
use ironrdp::core::PduParsing; use ironrdp::pdu::PduParsing;
use ironrdp::session::ErasedWriter; use ironrdp::session::ErasedWriter;
use tokio::sync::Mutex; use tokio::sync::Mutex;

View file

@ -9,8 +9,8 @@ use std::{io, process};
use futures_util::io::AsyncWriteExt as _; use futures_util::io::AsyncWriteExt as _;
use gui::MessagePassingGfxHandler; use gui::MessagePassingGfxHandler;
use ironrdp::dvc::gfx::ServerPdu;
use ironrdp::graphics::image_processing::PixelFormat; use ironrdp::graphics::image_processing::PixelFormat;
use ironrdp::pdu::dvc::gfx::ServerPdu;
use ironrdp::session::connection_sequence::{process_connection_sequence, UpgradedStream}; use ironrdp::session::connection_sequence::{process_connection_sequence, UpgradedStream};
use ironrdp::session::image::DecodedImage; use ironrdp::session::image::DecodedImage;
use ironrdp::session::{ActiveStageOutput, ActiveStageProcessor, ErasedWriter, RdpError}; use ironrdp::session::{ActiveStageOutput, ActiveStageProcessor, ErasedWriter, RdpError};

View file

@ -11,15 +11,16 @@ keywords = ["rdp", "client", "remote", "desktop", "protocol", "gfx", "rfx"]
[features] [features]
default = ["rustls"] default = ["rustls"]
rustls = ["dep:tokio-rustls", "ironrdp/rustls"] rustls = ["dep:tokio-rustls", "ironrdp-session/rustls"]
native-tls = ["dep:async-native-tls", "ironrdp/native-tls"] native-tls = ["dep:async-native-tls", "ironrdp-session/native-tls"]
[dependencies] [dependencies]
# Protocol # Protocols
ironrdp = { path = "../ironrdp" } ironrdp = { path = "../.." }
ironrdp-input = { path = "../ironrdp-input" } ironrdp-input = { path = "../input" }
sspi = { version = "0.8.0", features = ["network_client"] } # TODO: enable dns_resolver at some point ironrdp-session = { path = "../session" }
sspi = { version = "0.8", features = ["network_client"] } # TODO: enable dns_resolver at some point
# GUI # GUI
softbuffer = "0.2.0" softbuffer = "0.2.0"
@ -30,16 +31,18 @@ clap = { version = "4.0", features = ["derive", "cargo"] }
exitcode = "1.1.2" exitcode = "1.1.2"
inquire = "0.5.3" inquire = "0.5.3"
# logging # Logging
log = "0.4" log = "0.4"
fern = "0.6" fern = "0.6"
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
tracing = "0.1.37"
# SSL # SSL
x509-parser = "0.14" x509-parser = "0.14"
async-native-tls = { version = "0.4", default-features = false, features = [ "runtime-tokio" ], optional = true } async-native-tls = { version = "0.4", default-features = false, features = [ "runtime-tokio" ], optional = true }
tokio-rustls = { version = "0.23", features = ["dangerous_configuration"], optional = true } tokio-rustls = { version = "0.23", features = ["dangerous_configuration"], optional = true }
# async, futures # Async, futures
tokio = { version = "1", features = ["full"]} tokio = { version = "1", features = ["full"]}
tokio-util = { version = "0.7.4", features = ["compat"] } tokio-util = { version = "0.7.4", features = ["compat"] }
futures-util = "0.3" futures-util = "0.3"
@ -49,5 +52,3 @@ chrono = "0.4.23"
whoami = "1.2.3" whoami = "1.2.3"
anyhow = "1.0.68" anyhow = "1.0.68"
smallvec = "1.10.0" smallvec = "1.10.0"
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
tracing = "0.1.37"

View file

@ -26,11 +26,11 @@ enum SecurityProtocol {
} }
impl SecurityProtocol { impl SecurityProtocol {
fn parse(security_protocol: SecurityProtocol) -> ironrdp::core::SecurityProtocol { fn parse(security_protocol: SecurityProtocol) -> ironrdp::pdu::SecurityProtocol {
match security_protocol { match security_protocol {
SecurityProtocol::Ssl => ironrdp::core::SecurityProtocol::SSL, SecurityProtocol::Ssl => ironrdp::pdu::SecurityProtocol::SSL,
SecurityProtocol::Hybrid => ironrdp::core::SecurityProtocol::HYBRID, SecurityProtocol::Hybrid => ironrdp::pdu::SecurityProtocol::HYBRID,
SecurityProtocol::HybridEx => ironrdp::core::SecurityProtocol::HYBRID_EX, SecurityProtocol::HybridEx => ironrdp::pdu::SecurityProtocol::HYBRID_EX,
} }
} }
} }
@ -47,15 +47,15 @@ enum KeyboardType {
} }
impl KeyboardType { impl KeyboardType {
fn parse(keyboard_type: KeyboardType) -> ironrdp::gcc::KeyboardType { fn parse(keyboard_type: KeyboardType) -> ironrdp::pdu::gcc::KeyboardType {
match keyboard_type { match keyboard_type {
KeyboardType::IbmEnhanced => ironrdp::gcc::KeyboardType::IbmEnhanced, KeyboardType::IbmEnhanced => ironrdp::pdu::gcc::KeyboardType::IbmEnhanced,
KeyboardType::IbmPcAt => ironrdp::gcc::KeyboardType::IbmPcAt, KeyboardType::IbmPcAt => ironrdp::pdu::gcc::KeyboardType::IbmPcAt,
KeyboardType::IbmPcXt => ironrdp::gcc::KeyboardType::IbmPcXt, KeyboardType::IbmPcXt => ironrdp::pdu::gcc::KeyboardType::IbmPcXt,
KeyboardType::OlivettiIco => ironrdp::gcc::KeyboardType::OlivettiIco, KeyboardType::OlivettiIco => ironrdp::pdu::gcc::KeyboardType::OlivettiIco,
KeyboardType::Nokia1050 => ironrdp::gcc::KeyboardType::Nokia1050, KeyboardType::Nokia1050 => ironrdp::pdu::gcc::KeyboardType::Nokia1050,
KeyboardType::Nokia9140 => ironrdp::gcc::KeyboardType::Nokia9140, KeyboardType::Nokia9140 => ironrdp::pdu::gcc::KeyboardType::Nokia9140,
KeyboardType::Japanese => ironrdp::gcc::KeyboardType::Japanese, KeyboardType::Japanese => ironrdp::pdu::gcc::KeyboardType::Japanese,
} }
} }
} }

View file

@ -261,7 +261,7 @@ impl GuiContext {
fn send_fast_path_events( fn send_fast_path_events(
input_event_sender: &mpsc::UnboundedSender<RdpInputEvent>, input_event_sender: &mpsc::UnboundedSender<RdpInputEvent>,
input_events: smallvec::SmallVec<[ironrdp::core::input::fast_path::FastPathInputEvent; 2]>, input_events: smallvec::SmallVec<[ironrdp::pdu::input::fast_path::FastPathInputEvent; 2]>,
) { ) {
if !input_events.is_empty() { if !input_events.is_empty() {
let _ = input_event_sender.send(RdpInputEvent::FastPath(input_events)); let _ = input_event_sender.send(RdpInputEvent::FastPath(input_events));

View file

@ -1,15 +1,11 @@
#[macro_use] #[macro_use]
extern crate log; extern crate log;
use std::fs::OpenOptions;
use anyhow::Context as _; use anyhow::Context as _;
use ironrdp_client::config::Config; use ironrdp_client::config::Config;
use ironrdp_client::gui::GuiContext; use ironrdp_client::gui::GuiContext;
use ironrdp_client::rdp::{RdpClient, RdpInputEvent}; use ironrdp_client::rdp::{RdpClient, RdpInputEvent};
use tokio::runtime; use tokio::runtime;
use tracing_subscriber::prelude::__tracing_subscriber_SubscriberExt;
use tracing_subscriber::EnvFilter;
fn main() -> anyhow::Result<()> { fn main() -> anyhow::Result<()> {
let mut config = Config::parse_args().context("CLI arguments parsing")?; let mut config = Config::parse_args().context("CLI arguments parsing")?;
@ -63,6 +59,11 @@ fn setup_logging(log_file: &str) -> Result<(), fern::InitError> {
// sspi-rs logging // sspi-rs logging
if let Ok(path) = std::env::var("SSPI_LOG_FILE") { if let Ok(path) = std::env::var("SSPI_LOG_FILE") {
use std::fs::OpenOptions;
use tracing_subscriber::prelude::*;
use tracing_subscriber::EnvFilter;
let file = match OpenOptions::new().read(true).append(true).open(path) { let file = match OpenOptions::new().read(true).append(true).open(path) {
Ok(file) => file, Ok(file) => file,
Err(e) => { Err(e) => {

View file

@ -1,6 +1,6 @@
use futures_util::io::AsyncWriteExt as _; use futures_util::io::AsyncWriteExt as _;
use ironrdp::core::input::fast_path::FastPathInputEvent;
use ironrdp::graphics::image_processing::PixelFormat; use ironrdp::graphics::image_processing::PixelFormat;
use ironrdp::pdu::input::fast_path::FastPathInputEvent;
use ironrdp::session::connection_sequence::{process_connection_sequence, Address}; use ironrdp::session::connection_sequence::{process_connection_sequence, Address};
use ironrdp::session::image::DecodedImage; use ironrdp::session::image::DecodedImage;
use ironrdp::session::{ActiveStageOutput, ActiveStageProcessor, RdpError}; use ironrdp::session::{ActiveStageOutput, ActiveStageProcessor, RdpError};
@ -143,8 +143,8 @@ async fn run_impl(
return Ok(RdpControlFlow::ReconnectWithNewSize { width, height }) return Ok(RdpControlFlow::ReconnectWithNewSize { width, height })
}, },
RdpInputEvent::FastPath(events) => { RdpInputEvent::FastPath(events) => {
use ironrdp::core::input::fast_path::FastPathInput; use ironrdp::pdu::input::fast_path::FastPathInput;
use ironrdp::core::PduParsing as _; use ironrdp::pdu::PduParsing as _;
trace!("Inputs: {events:?}"); trace!("Inputs: {events:?}");
@ -159,7 +159,7 @@ async fn run_impl(
writer.write_all(&frame).await?; writer.write_all(&frame).await?;
} }
RdpInputEvent::Close => { RdpInputEvent::Close => {
// TODO: should we send a connection close to server? // TODO: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/27915739-8f77-487e-9927-55008af7fd68
break 'outer; break 'outer;
} }
} }

View file

@ -1,5 +1,5 @@
[package] [package]
name = "ironrdp-renderer" name = "ironrdp-glutin-renderer"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
readme = "README.md" readme = "README.md"
@ -8,13 +8,10 @@ homepage = "https://github.com/Devolutions/IronRDP"
repository = "https://github.com/Devolutions/IronRDP" repository = "https://github.com/Devolutions/IronRDP"
authors = ["Devolutions Inc. <infos@devolutions.net>"] authors = ["Devolutions Inc. <infos@devolutions.net>"]
[lib]
path = "src/lib.rs"
[dependencies] [dependencies]
ironrdp = { path = "../.." }
glow = "0.11" glow = "0.11"
log = "0.4" log = "0.4"
thiserror = "1.0.38" thiserror = "1.0.38"
ironrdp = { path = "../ironrdp" }
glutin = { version = "0.29" } glutin = { version = "0.29" }
openh264 = { version = "0.3" } openh264 = { version = "0.3" }

View file

@ -1,8 +1,8 @@
precision mediump float; precision mediump float;
uniform mat4 u_projection; uniform mat4 u_projection;
attribute vec2 a_position; attribute vec2 a_position;
void main(){ void main(){
gl_Position = u_projection * vec4(a_position, 0.0, 1.0); gl_Position = u_projection * vec4(a_position, 0.0, 1.0);
} }

View file

@ -1,35 +1,35 @@
precision lowp float; precision lowp float;
uniform vec2 screen_size; uniform vec2 screen_size;
uniform vec2 stride_scale; uniform vec2 stride_scale;
uniform sampler2D main_y_texture; uniform sampler2D main_y_texture;
uniform sampler2D main_u_texture; uniform sampler2D main_u_texture;
uniform sampler2D main_v_texture; uniform sampler2D main_v_texture;
uniform sampler2D aux_y_texture; uniform sampler2D aux_y_texture;
uniform sampler2D aux_u_texture; uniform sampler2D aux_u_texture;
uniform sampler2D aux_v_texture; uniform sampler2D aux_v_texture;
// YUV to RGB conversion matrix from https://github.com/mbebenita/Broadway/blob/master/Player/YUVCanvas.js // YUV to RGB conversion matrix from https://github.com/mbebenita/Broadway/blob/master/Player/YUVCanvas.js
const mat4 conversion = mat4( const mat4 conversion = mat4(
1.16438, 0.00000, 1.79274, -0.97295, 1.16438, 0.00000, 1.79274, -0.97295,
1.16438, -0.21325, -0.53291, 0.30148, 1.16438, -0.21325, -0.53291, 0.30148,
1.16438, 2.11240, 0.00000, -1.13340, 1.16438, 2.11240, 0.00000, -1.13340,
0, 0, 0, 1 0, 0, 0, 1
); );
void main(void) { void main(void) {
// Inverted image // Inverted image
vec2 coordinates = vec2(gl_FragCoord.x, screen_size.y - gl_FragCoord.y); vec2 coordinates = vec2(gl_FragCoord.x, screen_size.y - gl_FragCoord.y);
// Scale from [0..width, 0..height] to [0..1.0, 0..1.0] range and // Scale from [0..width, 0..height] to [0..1.0, 0..1.0] range and
// then scale to eliminate the stride padding // then scale to eliminate the stride padding
vec2 tex_coord = ((coordinates) / screen_size) * stride_scale; vec2 tex_coord = ((coordinates) / screen_size) * stride_scale;
float main_y_channel = texture2D(main_y_texture, tex_coord).x; float main_y_channel = texture2D(main_y_texture, tex_coord).x;
float main_u_channel = texture2D(main_u_texture, tex_coord).x; float main_u_channel = texture2D(main_u_texture, tex_coord).x;
float main_v_channel = texture2D(main_v_texture, tex_coord).x; float main_v_channel = texture2D(main_v_texture, tex_coord).x;
vec4 channels = vec4(main_y_channel, main_u_channel, main_v_channel, 1.0); vec4 channels = vec4(main_y_channel, main_u_channel, main_v_channel, 1.0);
gl_FragColor = channels * conversion; gl_FragColor = channels * conversion;
} }

View file

@ -1,77 +1,77 @@
precision lowp float; precision lowp float;
uniform vec2 screen_size; uniform vec2 screen_size;
uniform vec2 stride_scale; uniform vec2 stride_scale;
uniform sampler2D main_y_texture; uniform sampler2D main_y_texture;
uniform sampler2D main_u_texture; uniform sampler2D main_u_texture;
uniform sampler2D main_v_texture; uniform sampler2D main_v_texture;
uniform sampler2D aux_y_texture; uniform sampler2D aux_y_texture;
uniform sampler2D aux_u_texture; uniform sampler2D aux_u_texture;
uniform sampler2D aux_v_texture; uniform sampler2D aux_v_texture;
const vec2 CUTOFF = vec2(30.0/255.0, 30.0/255.0); const vec2 CUTOFF = vec2(30.0/255.0, 30.0/255.0);
// YUV to RGB conversion matrix from https://github.com/mbebenita/Broadway/blob/master/Player/YUVCanvas.js // YUV to RGB conversion matrix from https://github.com/mbebenita/Broadway/blob/master/Player/YUVCanvas.js
const mat4 conversion = mat4( const mat4 conversion = mat4(
1.16438, 0.00000, 1.79274, -0.97295, 1.16438, 0.00000, 1.79274, -0.97295,
1.16438, -0.21325, -0.53291, 0.30148, 1.16438, -0.21325, -0.53291, 0.30148,
1.16438, 2.11240, 0.00000, -1.13340, 1.16438, 2.11240, 0.00000, -1.13340,
0, 0, 0, 1 0, 0, 0, 1
); );
const vec2 half_offset = vec2(0.5, 0.5); const vec2 half_offset = vec2(0.5, 0.5);
void main(void) { void main(void) {
vec2 coordinates = vec2(gl_FragCoord.x, screen_size.y - gl_FragCoord.y) ; vec2 coordinates = vec2(gl_FragCoord.x, screen_size.y - gl_FragCoord.y) ;
vec2 main_tex_coord = (coordinates / screen_size) * stride_scale; vec2 main_tex_coord = (coordinates / screen_size) * stride_scale;
// Query the main view // Query the main view
float main_y_channel = texture2D(main_y_texture, main_tex_coord).x; float main_y_channel = texture2D(main_y_texture, main_tex_coord).x;
float main_u_channel = texture2D(main_u_texture, main_tex_coord).x; float main_u_channel = texture2D(main_u_texture, main_tex_coord).x;
float main_v_channel = texture2D(main_v_texture, main_tex_coord).x; float main_v_channel = texture2D(main_v_texture, main_tex_coord).x;
coordinates = coordinates - half_offset; coordinates = coordinates - half_offset;
float offset = floor(mod(coordinates.y, 16.0) * 0.5); float offset = floor(mod(coordinates.y, 16.0) * 0.5);
float start_y = offset + floor(coordinates.y / 16.0) * 16.0; float start_y = offset + floor(coordinates.y / 16.0) * 16.0;
// Auxiliary view // Auxiliary view
vec2 aux_tex_coord = vec2(coordinates.x, start_y) + half_offset; vec2 aux_tex_coord = vec2(coordinates.x, start_y) + half_offset;
vec2 aux_tex_coord_next = aux_tex_coord + vec2(1.0, 0.0); vec2 aux_tex_coord_next = aux_tex_coord + vec2(1.0, 0.0);
vec2 top_half = aux_tex_coord/screen_size * stride_scale; vec2 top_half = aux_tex_coord/screen_size * stride_scale;
vec2 top_half_next = aux_tex_coord_next/screen_size * stride_scale; vec2 top_half_next = aux_tex_coord_next/screen_size * stride_scale;
vec2 bottom_half = (aux_tex_coord + vec2(0.0, 8.0))/screen_size * stride_scale; vec2 bottom_half = (aux_tex_coord + vec2(0.0, 8.0))/screen_size * stride_scale;
vec2 bottom_half_next = (aux_tex_coord_next + vec2(0.0, 8.0))/screen_size * stride_scale; vec2 bottom_half_next = (aux_tex_coord_next + vec2(0.0, 8.0))/screen_size * stride_scale;
float aux_b4 = texture2D(aux_y_texture, top_half).x; float aux_b4 = texture2D(aux_y_texture, top_half).x;
float aux_b5 = texture2D(aux_y_texture, bottom_half).x; float aux_b5 = texture2D(aux_y_texture, bottom_half).x;
float next_u = texture2D(aux_y_texture, top_half_next).x; float next_u = texture2D(aux_y_texture, top_half_next).x;
float next_v = texture2D(aux_y_texture, bottom_half_next).x; float next_v = texture2D(aux_y_texture, bottom_half_next).x;
vec2 aux_uv_additional = vec2(next_u, next_v); vec2 aux_uv_additional = vec2(next_u, next_v);
float aux_b6 = texture2D(aux_u_texture, main_tex_coord).x; float aux_b6 = texture2D(aux_u_texture, main_tex_coord).x;
float aux_b7 = texture2D(aux_v_texture, main_tex_coord).x; float aux_b7 = texture2D(aux_v_texture, main_tex_coord).x;
float is_x_odd = mod(coordinates.x, 2.0); float is_x_odd = mod(coordinates.x, 2.0);
float is_y_odd = mod(coordinates.y, 2.0); float is_y_odd = mod(coordinates.y, 2.0);
float is_xy_even = (1.0 - is_x_odd) * (1.0 - is_y_odd); float is_xy_even = (1.0 - is_x_odd) * (1.0 - is_y_odd);
vec2 aux_uv_main = vec2(aux_b4, aux_b5); vec2 aux_uv_main = vec2(aux_b4, aux_b5);
vec2 aux_uv_secondary = vec2(aux_b6, aux_b7); vec2 aux_uv_secondary = vec2(aux_b6, aux_b7);
vec2 uv_channels = is_y_odd * aux_uv_main + (1.0 - is_y_odd) * is_x_odd * aux_uv_secondary; vec2 uv_channels = is_y_odd * aux_uv_main + (1.0 - is_y_odd) * is_x_odd * aux_uv_secondary;
// Apply the reverse filter when both (x, y) are even based on [MS-RDPEGFX] rule // Apply the reverse filter when both (x, y) are even based on [MS-RDPEGFX] rule
vec2 main_uv=vec2(main_u_channel, main_v_channel); vec2 main_uv=vec2(main_u_channel, main_v_channel);
vec2 uv_augmented = clamp(main_uv * 4.0 - aux_uv_main - aux_uv_secondary - aux_uv_additional, vec2(0.0, 0.0), vec2(1.0, 1.0)); vec2 uv_augmented = clamp(main_uv * 4.0 - aux_uv_main - aux_uv_secondary - aux_uv_additional, vec2(0.0, 0.0), vec2(1.0, 1.0));
vec2 uv_diff = abs(uv_augmented - main_uv); vec2 uv_diff = abs(uv_augmented - main_uv);
bvec2 uv_is_greater = greaterThan(uv_diff, CUTOFF); bvec2 uv_is_greater = greaterThan(uv_diff, CUTOFF);
vec2 uv_is_greater_vec = vec2(uv_is_greater.x, uv_is_greater.y); vec2 uv_is_greater_vec = vec2(uv_is_greater.x, uv_is_greater.y);
vec2 uv_touse = uv_augmented * uv_is_greater_vec + main_uv * (vec2(1.0, 1.0) - uv_is_greater_vec); vec2 uv_touse = uv_augmented * uv_is_greater_vec + main_uv * (vec2(1.0, 1.0) - uv_is_greater_vec);
vec2 final_uv_channels = is_xy_even * uv_touse + (1.0 - is_xy_even) * uv_channels; vec2 final_uv_channels = is_xy_even * uv_touse + (1.0 - is_xy_even) * uv_channels;
vec4 channels = vec4(main_y_channel, final_uv_channels.x, final_uv_channels.y, 1.0); vec4 channels = vec4(main_y_channel, final_uv_channels.x, final_uv_channels.y, 1.0);
vec3 rgb = (channels * conversion).xyz; vec3 rgb = (channels * conversion).xyz;
gl_FragColor = vec4(rgb, 1.0); gl_FragColor = vec4(rgb, 1.0);
} }

View file

@ -1,79 +1,79 @@
precision lowp float; precision lowp float;
uniform vec2 screen_size; uniform vec2 screen_size;
uniform vec2 stride_scale; uniform vec2 stride_scale;
uniform sampler2D main_y_texture; uniform sampler2D main_y_texture;
uniform sampler2D main_u_texture; uniform sampler2D main_u_texture;
uniform sampler2D main_v_texture; uniform sampler2D main_v_texture;
uniform sampler2D aux_y_texture; uniform sampler2D aux_y_texture;
uniform sampler2D aux_u_texture; uniform sampler2D aux_u_texture;
uniform sampler2D aux_v_texture; uniform sampler2D aux_v_texture;
const vec2 CUTOFF = vec2(30.0/255.0, 30.0/255.0); const vec2 CUTOFF = vec2(30.0/255.0, 30.0/255.0);
// YUV to RGB conversion matrix from https://github.com/mbebenita/Broadway/blob/master/Player/YUVCanvas.js // YUV to RGB conversion matrix from https://github.com/mbebenita/Broadway/blob/master/Player/YUVCanvas.js
const mat4 conversion = mat4( const mat4 conversion = mat4(
1.16438, 0.00000, 1.79274, -0.97295, 1.16438, 0.00000, 1.79274, -0.97295,
1.16438, -0.21325, -0.53291, 0.30148, 1.16438, -0.21325, -0.53291, 0.30148,
1.16438, 2.11240, 0.00000, -1.13340, 1.16438, 2.11240, 0.00000, -1.13340,
0, 0, 0, 1 0, 0, 0, 1
); );
const vec2 half_offset = vec2(0.5, 0.5); const vec2 half_offset = vec2(0.5, 0.5);
void main(void) { void main(void) {
vec2 coordinates = vec2(gl_FragCoord.x, screen_size.y - gl_FragCoord.y); vec2 coordinates = vec2(gl_FragCoord.x, screen_size.y - gl_FragCoord.y);
// Query the main view // Query the main view
vec2 main_tex_coord = (coordinates / screen_size) * stride_scale; vec2 main_tex_coord = (coordinates / screen_size) * stride_scale;
float main_y_channel = texture2D(main_y_texture, main_tex_coord).x; float main_y_channel = texture2D(main_y_texture, main_tex_coord).x;
float main_u_channel = texture2D(main_u_texture, main_tex_coord).x; float main_u_channel = texture2D(main_u_texture, main_tex_coord).x;
float main_v_channel = texture2D(main_v_texture, main_tex_coord).x; float main_v_channel = texture2D(main_v_texture, main_tex_coord).x;
coordinates = coordinates - half_offset; coordinates = coordinates - half_offset;
float left_x = coordinates.x * 0.5; float left_x = coordinates.x * 0.5;
float right_x = (screen_size.x + coordinates.x) * 0.5; float right_x = (screen_size.x + coordinates.x) * 0.5;
// Auxiliary view // Auxiliary view
// Left // Left
vec2 left_half = (vec2(left_x, coordinates.y) + half_offset)/screen_size * stride_scale; vec2 left_half = (vec2(left_x, coordinates.y) + half_offset)/screen_size * stride_scale;
float aux_ub4 = texture2D(aux_y_texture, left_half).x; float aux_ub4 = texture2D(aux_y_texture, left_half).x;
float aux_ub6 = texture2D(aux_u_texture, left_half).x; float aux_ub6 = texture2D(aux_u_texture, left_half).x;
float aux_ub8 = texture2D(aux_v_texture, left_half).x; float aux_ub8 = texture2D(aux_v_texture, left_half).x;
// Right // Right
vec2 right_half = (vec2(right_x, coordinates.y) + half_offset)/screen_size * stride_scale; vec2 right_half = (vec2(right_x, coordinates.y) + half_offset)/screen_size * stride_scale;
float aux_vb5 = texture2D(aux_y_texture, right_half).x; float aux_vb5 = texture2D(aux_y_texture, right_half).x;
float aux_vb7 = texture2D(aux_u_texture, right_half).x; float aux_vb7 = texture2D(aux_u_texture, right_half).x;
float aux_vb9 = texture2D(aux_v_texture, right_half).x; float aux_vb9 = texture2D(aux_v_texture, right_half).x;
// Create aux view // Create aux view
vec2 aux_uv_main = vec2(aux_ub4, aux_vb5); vec2 aux_uv_main = vec2(aux_ub4, aux_vb5);
vec2 aux_uv_left = vec2(aux_ub6, aux_vb7); vec2 aux_uv_left = vec2(aux_ub6, aux_vb7);
vec2 aux_uv_right = vec2(aux_ub8, aux_vb9); vec2 aux_uv_right = vec2(aux_ub8, aux_vb9);
float is_x_odd = mod(coordinates.x, 2.0); float is_x_odd = mod(coordinates.x, 2.0);
float is_y_odd = mod(coordinates.y, 2.0); float is_y_odd = mod(coordinates.y, 2.0);
float is_xy_even = (1.0 - is_x_odd) * (1.0 - is_y_odd); float is_xy_even = (1.0 - is_x_odd) * (1.0 - is_y_odd);
float is_x_mod_4 = float(mod(coordinates.x, 4.0) < 1.0); float is_x_mod_4 = float(mod(coordinates.x, 4.0) < 1.0);
// If x is odd then b4,b5 have data // If x is odd then b4,b5 have data
// else if y is odd then b6,b7 have data when x is divisible by 4 // else if y is odd then b6,b7 have data when x is divisible by 4
// else b8,b9 have data // else b8,b9 have data
vec2 uv_channels = is_x_odd * aux_uv_main + (1.0 - is_x_odd) * is_y_odd * (is_x_mod_4 * aux_uv_left + (1.0 - is_x_mod_4) * aux_uv_right); vec2 uv_channels = is_x_odd * aux_uv_main + (1.0 - is_x_odd) * is_y_odd * (is_x_mod_4 * aux_uv_left + (1.0 - is_x_mod_4) * aux_uv_right);
// Apply the reverse filter when both (x, y) are even based on [MS-RDPEGFX] rule // Apply the reverse filter when both (x, y) are even based on [MS-RDPEGFX] rule
vec2 main_uv=vec2(main_u_channel, main_v_channel); vec2 main_uv=vec2(main_u_channel, main_v_channel);
vec2 uv_augmented = clamp(main_uv * 4.0 - aux_uv_main - aux_uv_left - aux_uv_right, vec2(0.0, 0.0), vec2(1.0, 1.0)); vec2 uv_augmented = clamp(main_uv * 4.0 - aux_uv_main - aux_uv_left - aux_uv_right, vec2(0.0, 0.0), vec2(1.0, 1.0));
vec2 uv_diff = abs(uv_augmented - main_uv); vec2 uv_diff = abs(uv_augmented - main_uv);
bvec2 uv_is_greater = greaterThan(uv_diff, CUTOFF); bvec2 uv_is_greater = greaterThan(uv_diff, CUTOFF);
vec2 uv_is_greater_vec = vec2(uv_is_greater.x, uv_is_greater.y); vec2 uv_is_greater_vec = vec2(uv_is_greater.x, uv_is_greater.y);
vec2 uv_touse = uv_augmented * uv_is_greater_vec + main_uv * (vec2(1.0, 1.0) - uv_is_greater_vec); vec2 uv_touse = uv_augmented * uv_is_greater_vec + main_uv * (vec2(1.0, 1.0) - uv_is_greater_vec);
vec2 final_uv_channels = is_xy_even * uv_touse + (1.0 - is_xy_even) * uv_channels; vec2 final_uv_channels = is_xy_even * uv_touse + (1.0 - is_xy_even) * uv_channels;
vec4 channels = vec4(main_y_channel, final_uv_channels.x, final_uv_channels.y, 1.0); vec4 channels = vec4(main_y_channel, final_uv_channels.x, final_uv_channels.y, 1.0);
vec3 rgb = (channels * conversion).xyz; vec3 rgb = (channels * conversion).xyz;
gl_FragColor = vec4(rgb, 1.0); gl_FragColor = vec4(rgb, 1.0);
} }

View file

@ -1,9 +1,9 @@
precision lowp float; precision lowp float;
varying vec2 v_texCoord; varying vec2 v_texCoord;
uniform sampler2D screen_texture; uniform sampler2D screen_texture;
void main(void) { void main(void) {
vec4 color = texture2D(screen_texture, v_texCoord); vec4 color = texture2D(screen_texture, v_texCoord);
gl_FragColor = color; gl_FragColor = color;
} }

View file

@ -1,10 +1,10 @@
precision mediump float; precision mediump float;
attribute vec2 a_position; attribute vec2 a_position;
attribute vec2 a_tex_coord; attribute vec2 a_tex_coord;
varying vec2 v_texCoord; varying vec2 v_texCoord;
void main(){ void main(){
v_texCoord = a_tex_coord; v_texCoord = a_tex_coord;
gl_Position = vec4(a_position, 0.0, 1.0); gl_Position = vec4(a_position, 0.0, 1.0);
} }

View file

@ -4,7 +4,7 @@ use std::slice::from_raw_parts;
use std::sync::Arc; use std::sync::Arc;
use glow::*; use glow::*;
use ironrdp::geometry::Rectangle; use ironrdp::pdu::geometry::Rectangle;
fn cast_as_bytes<T>(input: &[T]) -> &[u8] { fn cast_as_bytes<T>(input: &[T]) -> &[u8] {
unsafe { from_raw_parts(input.as_ptr() as *const u8, input.len() * size_of::<T>()) } unsafe { from_raw_parts(input.as_ptr() as *const u8, input.len() * size_of::<T>()) }

View file

@ -7,10 +7,10 @@ use std::thread;
use std::thread::JoinHandle; use std::thread::JoinHandle;
use glutin::dpi::PhysicalSize; use glutin::dpi::PhysicalSize;
use ironrdp::dvc::gfx; use ironrdp::pdu::dvc::gfx;
use ironrdp::dvc::gfx::{Codec1Type, ServerPdu}; use ironrdp::pdu::dvc::gfx::{Codec1Type, ServerPdu};
use ironrdp::geometry::Rectangle; use ironrdp::pdu::geometry::Rectangle;
use ironrdp::PduParsing; use ironrdp::pdu::PduParsing;
use log::info; use log::info;
use thiserror::Error; use thiserror::Error;

View file

@ -3,12 +3,12 @@ use std::fmt::Debug;
use std::sync::Arc; use std::sync::Arc;
use glow::Context; use glow::Context;
use ironrdp::core::dvc::gfx::{ use ironrdp::pdu::dvc::gfx::{
Avc420BitmapStream, Avc444BitmapStream, Codec1Type, CreateSurfacePdu, Encoding, GraphicsPipelineError, PixelFormat, Avc420BitmapStream, Avc444BitmapStream, Codec1Type, CreateSurfacePdu, Encoding, GraphicsPipelineError, PixelFormat,
WireToSurface1Pdu, WireToSurface1Pdu,
}; };
use ironrdp::core::PduBufferParsing; use ironrdp::pdu::geometry::Rectangle;
use ironrdp::geometry::Rectangle; use ironrdp::pdu::PduBufferParsing;
use log::error; use log::error;
use openh264::decoder::{DecodedYUV, Decoder}; use openh264::decoder::{DecodedYUV, Decoder};
@ -58,7 +58,7 @@ impl SurfaceDecoders {
.get_mut(&pdu.surface_id) .get_mut(&pdu.surface_id)
.ok_or(RendererError::InvalidSurfaceId(pdu.surface_id))?; .ok_or(RendererError::InvalidSurfaceId(pdu.surface_id))?;
match pdu.codec_id { match pdu.codec_id {
ironrdp::dvc::gfx::Codec1Type::Avc420 => { ironrdp::pdu::dvc::gfx::Codec1Type::Avc420 => {
let packet = Avc420BitmapStream::from_buffer_consume(&mut pdu.bitmap_data.as_slice()) let packet = Avc420BitmapStream::from_buffer_consume(&mut pdu.bitmap_data.as_slice())
.map_err(GraphicsPipelineError::from)?; .map_err(GraphicsPipelineError::from)?;
let yuv = decoder.decode(packet.data)?.ok_or(RendererError::DecodeError)?; let yuv = decoder.decode(packet.data)?.ok_or(RendererError::DecodeError)?;
@ -77,7 +77,7 @@ impl SurfaceDecoders {
dimensions, dimensions,
}) })
} }
ironrdp::dvc::gfx::Codec1Type::Avc444 | ironrdp::dvc::gfx::Codec1Type::Avc444v2 => { ironrdp::pdu::dvc::gfx::Codec1Type::Avc444 | ironrdp::pdu::dvc::gfx::Codec1Type::Avc444v2 => {
let packet = Avc444BitmapStream::from_buffer_consume(&mut pdu.bitmap_data.as_slice()) let packet = Avc444BitmapStream::from_buffer_consume(&mut pdu.bitmap_data.as_slice())
.map_err(GraphicsPipelineError::from)?; .map_err(GraphicsPipelineError::from)?;
let yuv = decoder.decode(packet.stream1.data)?.ok_or(RendererError::DecodeError)?; let yuv = decoder.decode(packet.stream1.data)?.ok_or(RendererError::DecodeError)?;
@ -304,7 +304,7 @@ impl Surfaces {
pub(crate) fn map_surface_to_scaled_output( pub(crate) fn map_surface_to_scaled_output(
&mut self, &mut self,
pdu: ironrdp::dvc::gfx::MapSurfaceToScaledOutputPdu, pdu: ironrdp::pdu::dvc::gfx::MapSurfaceToScaledOutputPdu,
) -> Result<()> { ) -> Result<()> {
let surface = self.get_surface(pdu.surface_id)?; let surface = self.get_surface(pdu.surface_id)?;
surface.set_location(Rectangle { surface.set_location(Rectangle {

View file

@ -9,7 +9,7 @@ repository = "https://github.com/Devolutions/IronRDP"
authors = ["Devolutions Inc. <infos@devolutions.net>"] authors = ["Devolutions Inc. <infos@devolutions.net>"]
[dependencies] [dependencies]
ironrdp-core = { path = "../ironrdp-core" } ironrdp-pdu = { path = "../pdu" }
num-traits = "0.2.15" num-traits = "0.2.15"
num-derive = "0.3.3" num-derive = "0.3.3"
byteorder = "1.4.3" byteorder = "1.4.3"

View file

@ -1,4 +1,4 @@
use ironrdp_core::utils::SplitTo as _; use ironrdp_pdu::utils::SplitTo as _;
pub fn decode(buffer: &mut [i16], temp_buffer: &mut [i16]) { pub fn decode(buffer: &mut [i16], temp_buffer: &mut [i16]) {
decode_block(&mut buffer[3840..], temp_buffer, 8); decode_block(&mut buffer[3840..], temp_buffer, 8);

View file

@ -1,7 +1,7 @@
use std::io; use std::io;
use byteorder::WriteBytesExt; use byteorder::WriteBytesExt;
use ironrdp_core::geometry::Rectangle; use ironrdp_pdu::geometry::Rectangle;
use num_derive::ToPrimitive; use num_derive::ToPrimitive;
use num_traits::ToPrimitive as _; use num_traits::ToPrimitive as _;

View file

@ -1,4 +1,4 @@
use ironrdp_core::codecs::rfx::Quant; use ironrdp_pdu::codecs::rfx::Quant;
const FIRST_LEVEL_SIZE: usize = 1024; const FIRST_LEVEL_SIZE: usize = 1024;
const SECOND_LEVEL_SIZE: usize = 256; const SECOND_LEVEL_SIZE: usize = 256;

View file

@ -1,6 +1,6 @@
use std::cmp::{max, min}; use std::cmp::{max, min};
use ironrdp_core::geometry::Rectangle; use ironrdp_pdu::geometry::Rectangle;
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Region { pub struct Region {

View file

@ -4,7 +4,7 @@ use std::io;
use bitvec::field::BitField as _; use bitvec::field::BitField as _;
use bitvec::order::Msb0; use bitvec::order::Msb0;
use bitvec::slice::BitSlice; use bitvec::slice::BitSlice;
use ironrdp_core::codecs::rfx::EntropyAlgorithm; use ironrdp_pdu::codecs::rfx::EntropyAlgorithm;
use thiserror::Error; use thiserror::Error;
use crate::utils::Bits; use crate::utils::Bits;

View file

@ -1,7 +1,7 @@
use std::io; use std::io;
use ironrdp_core::geometry::Rectangle;
use ironrdp_graphics::image_processing::*; use ironrdp_graphics::image_processing::*;
use ironrdp_pdu::geometry::Rectangle;
use proptest::prelude::*; use proptest::prelude::*;
fn bgra_to_rgba(input: &[u8], mut output: &mut [u8]) -> io::Result<()> { fn bgra_to_rgba(input: &[u8], mut output: &mut [u8]) -> io::Result<()> {

View file

@ -1,5 +1,5 @@
use ironrdp_core::codecs::rfx::EntropyAlgorithm;
use ironrdp_graphics::rlgr::*; use ironrdp_graphics::rlgr::*;
use ironrdp_pdu::codecs::rfx::EntropyAlgorithm;
#[test] #[test]
fn decode_works_with_rlgr3() { fn decode_works_with_rlgr3() {

View file

@ -9,8 +9,8 @@ repository = "https://github.com/Devolutions/IronRDP"
authors = ["Devolutions Inc. <infos@devolutions.net>"] authors = ["Devolutions Inc. <infos@devolutions.net>"]
[dependencies] [dependencies]
ironrdp-pdu = { path = "../pdu" }
bitvec = "1.0.1" bitvec = "1.0.1"
ironrdp-core = { path = "../ironrdp-core" }
smallvec = "1.10.0" smallvec = "1.10.0"
[dev-dependencies] [dev-dependencies]

View file

@ -1,9 +1,9 @@
use bitvec::array::BitArray; use bitvec::array::BitArray;
use bitvec::BitArr; use bitvec::BitArr;
use ironrdp_core::input::fast_path::{FastPathInputEvent, KeyboardFlags}; use ironrdp_pdu::input::fast_path::{FastPathInputEvent, KeyboardFlags};
use ironrdp_core::input::mouse::PointerFlags; use ironrdp_pdu::input::mouse::PointerFlags;
use ironrdp_core::input::mouse_x::PointerXFlags; use ironrdp_pdu::input::mouse_x::PointerXFlags;
use ironrdp_core::input::{MousePdu, MouseXPdu}; use ironrdp_pdu::input::{MousePdu, MouseXPdu};
use smallvec::SmallVec; use smallvec::SmallVec;
// TODO: unicode keyboard event support // TODO: unicode keyboard event support
@ -345,7 +345,7 @@ impl Database {
/// Returns the RDP input event to send in order to synchronize lock keys. /// Returns the RDP input event to send in order to synchronize lock keys.
pub fn synchronize_event(scroll_lock: bool, num_lock: bool, caps_lock: bool, kana_lock: bool) -> FastPathInputEvent { pub fn synchronize_event(scroll_lock: bool, num_lock: bool, caps_lock: bool, kana_lock: bool) -> FastPathInputEvent {
use ironrdp_core::input::fast_path::SynchronizeFlags; use ironrdp_pdu::input::fast_path::SynchronizeFlags;
let mut flags = SynchronizeFlags::empty(); let mut flags = SynchronizeFlags::empty();

View file

@ -1,8 +1,8 @@
use ironrdp_core::input::fast_path::{FastPathInputEvent, KeyboardFlags, SynchronizeFlags};
use ironrdp_core::input::mouse::PointerFlags;
use ironrdp_core::input::mouse_x::PointerXFlags;
use ironrdp_core::input::{MousePdu, MouseXPdu};
use ironrdp_input::*; use ironrdp_input::*;
use ironrdp_pdu::input::fast_path::{FastPathInputEvent, KeyboardFlags, SynchronizeFlags};
use ironrdp_pdu::input::mouse::PointerFlags;
use ironrdp_pdu::input::mouse_x::PointerXFlags;
use ironrdp_pdu::input::{MousePdu, MouseXPdu};
use rstest::rstest; use rstest::rstest;
enum MouseFlags { enum MouseFlags {

View file

@ -1,6 +1,6 @@
use anyhow::{bail, ensure}; use anyhow::{bail, ensure};
use ironrdp_core::input::fast_path::{FastPathInputEvent, KeyboardFlags};
use ironrdp_input::*; use ironrdp_input::*;
use ironrdp_pdu::input::fast_path::{FastPathInputEvent, KeyboardFlags};
use proptest::collection::vec; use proptest::collection::vec;
use proptest::prelude::*; use proptest::prelude::*;

View file

@ -0,0 +1,9 @@
[package]
name = "ironrdp-pdu-generators"
version = "0.0.0"
edition = "2021"
publish = false
[dependencies]
ironrdp-pdu = { path = "../pdu" }
proptest = "1.1.0"

View file

@ -0,0 +1,14 @@
pub fn add(left: usize, right: usize) -> usize {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}

View file

@ -1,5 +1,5 @@
[package] [package]
name = "ironrdp-core" name = "ironrdp-pdu"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
readme = "README.md" readme = "README.md"

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