From 246cc4661cdba68dc67ab8d3db285ccf39421295 Mon Sep 17 00:00:00 2001 From: Brian Lambert Date: Tue, 3 Oct 2023 17:49:22 -0700 Subject: [PATCH 1/7] New help proxy server --- Cargo.lock | 725 +++++++++++++++++++++++++++++++++-- crates/ark/Cargo.toml | 5 +- crates/ark/src/browser.rs | 3 +- crates/ark/src/help_proxy.rs | 398 ++++++++++++++++--- crates/ark/src/modules.rs | 10 +- 5 files changed, 1059 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f73c67dbd3..e44b2ebaf3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,185 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "actix-codec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" +dependencies = [ + "bitflags 1.3.2", + "bytes", + "futures-core", + "futures-sink", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "actix-http" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92ef85799cba03f76e4f7c10f533e66d87c9a7e7055f3391f09000ad8351bc9" +dependencies = [ + "actix-codec", + "actix-rt", + "actix-service", + "actix-utils", + "ahash", + "base64", + "bitflags 2.4.0", + "brotli", + "bytes", + "bytestring", + "derive_more", + "encoding_rs", + "flate2", + "futures-core", + "h2", + "http", + "httparse", + "httpdate", + "itoa", + "language-tags", + "local-channel", + "mime", + "percent-encoding", + "pin-project-lite", + "rand 0.8.5", + "sha1", + "smallvec", + "tokio", + "tokio-util", + "tracing", + "zstd", +] + +[[package]] +name = "actix-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" +dependencies = [ + "quote", + "syn 2.0.29", +] + +[[package]] +name = "actix-router" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799" +dependencies = [ + "bytestring", + "http", + "regex", + "serde", + "tracing", +] + +[[package]] +name = "actix-rt" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" +dependencies = [ + "futures-core", + "tokio", +] + +[[package]] +name = "actix-server" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb13e7eef0423ea6eab0e59f6c72e7cb46d33691ad56a726b3cd07ddec2c2d4" +dependencies = [ + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "futures-util", + "mio", + "socket2 0.5.4", + "tokio", + "tracing", +] + +[[package]] +name = "actix-service" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" +dependencies = [ + "futures-core", + "paste", + "pin-project-lite", +] + +[[package]] +name = "actix-utils" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" +dependencies = [ + "local-waker", + "pin-project-lite", +] + +[[package]] +name = "actix-web" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4a5b5e29603ca8c94a77c65cf874718ceb60292c5a5c3e5f4ace041af462b9" +dependencies = [ + "actix-codec", + "actix-http", + "actix-macros", + "actix-router", + "actix-rt", + "actix-server", + "actix-service", + "actix-utils", + "actix-web-codegen", + "ahash", + "bytes", + "bytestring", + "cfg-if", + "cookie", + "derive_more", + "encoding_rs", + "futures-core", + "futures-util", + "itoa", + "language-tags", + "log", + "mime", + "once_cell", + "pin-project-lite", + "regex", + "serde", + "serde_json", + "serde_urlencoded", + "smallvec", + "socket2 0.5.4", + "time 0.3.22", + "url", +] + +[[package]] +name = "actix-web-codegen" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1f50ebbb30eca122b188319a4398b3f7bb4a8cdf50ecfb73bfc6a3c3ce54f5" +dependencies = [ + "actix-router", + "proc-macro2", + "quote", + "syn 2.0.29", +] + [[package]] name = "addr2line" version = "0.19.0" @@ -17,6 +196,18 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "getrandom 0.2.9", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "1.0.1" @@ -26,6 +217,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + [[package]] name = "amalthea" version = "0.1.0" @@ -86,8 +292,9 @@ dependencies = [ [[package]] name = "ark" -version = "0.1.11" +version = "0.1.12" dependencies = [ + "actix-web", "amalthea", "anyhow", "async-trait", @@ -113,6 +320,7 @@ dependencies = [ "once_cell", "parking_lot", "regex", + "reqwest", "ropey", "scraper", "serde", @@ -122,6 +330,7 @@ dependencies = [ "tower-lsp", "tree-sitter", "tree-sitter-r", + "url", "uuid", "walkdir", "yaml-rust", @@ -166,7 +375,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.6.2", "object", "rustc-demangle", ] @@ -183,7 +392,7 @@ version = "0.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cexpr", "clang-sys", "lazy_static", @@ -205,6 +414,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + [[package]] name = "block-buffer" version = "0.10.4" @@ -214,6 +429,27 @@ dependencies = [ "generic-array", ] +[[package]] +name = "brotli" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da74e2b81409b1b743f8f0c62cc6254afefb8b8e50bbfe3735550f7aeefa3448" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "bumpalo" version = "3.12.2" @@ -243,6 +479,15 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +[[package]] +name = "bytestring" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "238e4886760d98c4f899360c834fa93e62cf7f721ac3c2da375cbdf4b8679aae" +dependencies = [ + "bytes", +] + [[package]] name = "c2rust-bitfields" version = "0.17.0" @@ -340,6 +585,27 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "cookie" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" +dependencies = [ + "percent-encoding", + "time 0.3.22", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.4" @@ -355,6 +621,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam" version = "0.8.2" @@ -621,6 +896,15 @@ version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + [[package]] name = "env_logger" version = "0.10.0" @@ -655,6 +939,12 @@ dependencies = [ "libc", ] +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + [[package]] name = "filetime" version = "0.2.21" @@ -667,17 +957,42 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "flate2" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" +dependencies = [ + "crc32fast", + "miniz_oxide 0.7.1", +] + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -1013,13 +1328,26 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.9", "tokio", "tower-service", "tracing", "want", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "iana-time-zone" version = "0.1.56" @@ -1051,9 +1379,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1076,7 +1404,7 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" dependencies = [ - "bitflags", + "bitflags 1.3.2", "inotify-sys", "libc", ] @@ -1101,6 +1429,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ipnet" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" + [[package]] name = "is-terminal" version = "0.4.7" @@ -1109,7 +1443,7 @@ checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", - "rustix", + "rustix 0.37.19", "windows-sys 0.48.0", ] @@ -1172,10 +1506,16 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8367585489f01bc55dd27404dcf56b95e6da061a256a666ab23be9ba96a2e587" dependencies = [ - "bitflags", + "bitflags 1.3.2", "libc", ] +[[package]] +name = "language-tags" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" + [[package]] name = "lazy_static" version = "1.4.0" @@ -1226,6 +1566,29 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" +[[package]] +name = "linux-raw-sys" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3852614a3bd9ca9804678ba6be5e3b8ce76dfc902cae004e3e0c44051b6e88db" + +[[package]] +name = "local-channel" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a493488de5f18c8ffcba89eebb8532ffc562dc400490eb65b84893fae0b178" +dependencies = [ + "futures-core", + "futures-sink", + "local-waker", +] + +[[package]] +name = "local-waker" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" + [[package]] name = "lock_api" version = "0.4.9" @@ -1257,7 +1620,7 @@ version = "0.94.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b63735a13a1f9cd4f4835223d828ed9c2e35c8c5e61837774399f558b6a1237" dependencies = [ - "bitflags", + "bitflags 1.3.2", "serde", "serde_json", "serde_repr", @@ -1314,6 +1677,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1329,6 +1698,15 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.8.6" @@ -1341,6 +1719,24 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "new_debug_unreachable" version = "1.0.4" @@ -1353,7 +1749,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", "memoffset 0.7.1", @@ -1383,7 +1779,7 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d9ba6c734de18ca27c8cef5cd7058aa4ac9f63596131e4c7e41e579319032a2" dependencies = [ - "bitflags", + "bitflags 1.3.2", "crossbeam-channel", "filetime", "fsevent-sys", @@ -1439,6 +1835,50 @@ version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +[[package]] +name = "openssl" +version = "0.10.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +dependencies = [ + "bitflags 2.4.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "parking_lot" version = "0.12.1" @@ -1473,6 +1913,12 @@ dependencies = [ "windows-targets 0.48.0", ] +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "peeking_take_while" version = "0.1.2" @@ -1481,9 +1927,9 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "phf" @@ -1793,7 +2239,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1802,7 +2248,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1833,6 +2279,44 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" +[[package]] +name = "reqwest" +version = "0.11.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + [[package]] name = "ropey" version = "1.6.0" @@ -1870,11 +2354,24 @@ version = "0.37.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.3.7", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac5ffa1efe7548069688cd7028f32591853cd7b5b756d41bcffd2353e4fc75b4" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys 0.4.8", "windows-sys 0.48.0", ] @@ -1899,6 +2396,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -1921,13 +2427,36 @@ dependencies = [ "tendril", ] +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "selectors" version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cssparser", "derive_more", "fxhash", @@ -1996,6 +2525,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_with" version = "3.0.0" @@ -2034,6 +2575,17 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.6" @@ -2091,6 +2643,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -2197,6 +2759,27 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "system-deps" version = "6.1.0" @@ -2216,6 +2799,19 @@ version = "0.12.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5" +[[package]] +name = "tempfile" +version = "3.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.3.5", + "rustix 0.38.3", + "windows-sys 0.48.0", +] + [[package]] name = "tendril" version = "0.4.3" @@ -2323,7 +2919,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.4.9", "tokio-macros", "windows-sys 0.48.0", ] @@ -2339,6 +2935,16 @@ dependencies = [ "syn 2.0.29", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.8" @@ -2454,6 +3060,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2539,9 +3146,9 @@ checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "url" -version = "2.3.1" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", "idna", @@ -2564,6 +3171,12 @@ dependencies = [ "getrandom 0.2.9", ] +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version-compare" version = "0.1.1" @@ -2639,6 +3252,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.86" @@ -2668,6 +3293,16 @@ version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" +[[package]] +name = "web-sys" +version = "0.3.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "which" version = "4.4.0" @@ -2860,6 +3495,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "yaml-rust" version = "0.4.5" @@ -2885,7 +3530,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd3091dd571fb84a9b3e5e5c6a807d186c411c812c8618786c3c30e5349234e7" dependencies = [ - "bitflags", + "bitflags 1.3.2", "libc", "zmq-sys", ] @@ -2900,3 +3545,33 @@ dependencies = [ "system-deps", "zeromq-src", ] + +[[package]] +name = "zstd" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "6.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.8+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" +dependencies = [ + "cc", + "libc", + "pkg-config", +] diff --git a/crates/ark/Cargo.toml b/crates/ark/Cargo.toml index e57b8ddd64..ed925d9237 100644 --- a/crates/ark/Cargo.toml +++ b/crates/ark/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ark" -version = "0.1.11" +version = "0.1.12" edition = "2021" rust-version = "1.70.0" description = """ @@ -8,6 +8,7 @@ The Amalthea R Kernel. """ [dependencies] +actix-web = "4.4.0" amalthea = { path = "../amalthea" } anyhow = { version = "^1.0", features = ["backtrace"] } async-trait = "0.1.66" @@ -33,6 +34,7 @@ notify = "6.0.0" once_cell = "1.17.1" parking_lot = "0.12.1" regex = "1.7.1" +reqwest = { version = "0.11.20", features = ["json"] } ropey = "1.6.0" scraper = "0.15.0" serde = { version = "1.0.183", features = ["derive"] } @@ -43,6 +45,7 @@ tower-lsp = "0.19.0" tree-sitter = "0.20.9" tree-sitter-r = { git = "https://github.com/r-lib/tree-sitter-r", branch = "next" } uuid = "1.3.0" +url = "2.4.1" walkdir = "2" yaml-rust = "0.4.5" diff --git a/crates/ark/src/browser.rs b/crates/ark/src/browser.rs index 63253c2906..6ade163fa6 100644 --- a/crates/ark/src/browser.rs +++ b/crates/ark/src/browser.rs @@ -5,6 +5,7 @@ // // +use std::convert::TryFrom; use std::process::Command; use amalthea::events::PositronEvent; @@ -31,7 +32,7 @@ pub unsafe extern "C" fn ps_browse_url(url: SEXP) -> SEXP { unsafe fn handle_help_url(url: &str) -> Result { // Check for help URLs - let port = RFunction::new("tools", "httpdPort").call()?.to::()?; + let port = u16::try_from(RFunction::new("tools", "httpdPort").call()?.to::()?)?; let prefix = format!("http://127.0.0.1:{}/", port); if !url.starts_with(&prefix) { return Ok(false); diff --git a/crates/ark/src/help_proxy.rs b/crates/ark/src/help_proxy.rs index 4857ec03fb..ac5d649210 100644 --- a/crates/ark/src/help_proxy.rs +++ b/crates/ark/src/help_proxy.rs @@ -5,72 +5,370 @@ // // -use std::net::Ipv4Addr; -use std::net::SocketAddr; - -use http::*; -use hyper::client::conn::handshake; -use hyper::server::conn::Http; -use hyper::service::service_fn; -use hyper::Body; +use std::net::TcpListener; + +use actix_web::get; +use actix_web::web; +use actix_web::App; +use actix_web::HttpResponse; +use actix_web::HttpServer; use stdext::spawn; -use tokio::net::TcpListener; -use tokio::net::TcpStream; +use url::Url; use crate::browser; -async fn handle_request(request: Request, port: i32) -> anyhow::Result> { - // connect to R help server - let addr = format!("localhost:{}", port); - let stream = TcpStream::connect(addr.as_str()).await?; - let (mut sender, conn) = handshake(stream).await?; - - // spawn a task to poll the connection and drive the HTTP state - tokio::spawn(async move { - if let Err(error) = conn.await { - log::error!("HELP PROXY ERROR: {}", error); +// Starts the help proxy. +pub fn start(target_port: u16) { + spawn!("ark-help-proxy", move || { + match task(target_port) { + Ok(value) => log::info!("Help proxy server exited with value: {:?}", value), + Err(error) => log::error!("Help proxy server exited unexpectedly: {}", error), } }); +} - // send the request - let response = sender.send_request(request).await?; +// The help proxy main entry point. +#[tokio::main] +async fn task(target_port: u16) -> anyhow::Result<()> { + // Create the help proxy. + let help_proxy = HelpProxy::new(target_port)?; - // forward the response - Ok(response) + // Set the help proxy port. + unsafe { browser::PORT = help_proxy.source_port }; + + // Run the help proxy. + Ok(help_proxy.run().await?) } -#[tokio::main] -async fn task(port: i32) -> anyhow::Result<()> { - let addr = SocketAddr::new(std::net::IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0); - let listener = TcpListener::bind(addr).await?; - - if let Ok(addr) = listener.local_addr() { - let port = addr.port(); - log::info!("Help proxy listening on port {}", port); - unsafe { browser::PORT = port }; +// AppState struct. +#[derive(Clone)] +struct AppState { + pub target_port: u16, +} + +// HelpProxy struct. +struct HelpProxy { + pub source_port: u16, + pub target_port: u16, +} + +// HelpProxy implementation. +impl HelpProxy { + // Creates a new HelpProxy. + pub fn new(target_port: u16) -> anyhow::Result { + Ok(HelpProxy { + source_port: TcpListener::bind("127.0.0.1:0")?.local_addr()?.port(), + target_port, + }) + } + + // Runs the HelpProxy. + pub async fn run(&self) -> anyhow::Result<()> { + // Create the app state. + let app_state = web::Data::new(AppState { + target_port: self.target_port, + }); + + // Create the server. + let server = HttpServer::new(move || { + App::new() + .app_data(app_state.clone()) + .service(proxy_request) + }) + .bind(("127.0.0.1", self.source_port))?; + + // Run the server. + Ok(server.run().await?) } +} + +// Proxies a request. +#[get("/{url:.*}")] +async fn proxy_request(path: web::Path<(String,)>, app_state: web::Data) -> HttpResponse { + // Get the URL path. + let (path,) = path.into_inner(); + + // Construct the target URL string. + let target_url_string = format!("http://localhost:{}/{path}", app_state.target_port); + + // Parse the target URL string into the target URL. + let target_url = match Url::parse(&target_url_string) { + Ok(url) => url, + Err(error) => { + log::info!("Error proxying {}: {}", target_url_string, error); + return HttpResponse::BadGateway().finish(); + }, + }; + + // Get the target URL. + match reqwest::get(target_url.clone()).await { + // OK. + Ok(response) => { + // We only handle OK. Everything else is unexpected. + if response.status() != reqwest::StatusCode::OK { + return HttpResponse::BadGateway().finish(); + } + + // Get the headers we need. + let headers = response.headers().clone(); + let content_type = headers.get("content-type"); - loop { - let (stream, _) = listener.accept().await?; - tokio::spawn(async move { - let http = Http::new(); - let status = http.serve_connection( - stream, - service_fn(|request| async move { handle_request(request, port).await }), + // Log. + log::info!( + "Proxing URL '{:?}' path '{}' content-type is '{:?}'", + target_url.to_string(), + target_url.path(), + content_type, ); - if let Err(error) = status.await { - log::error!("HELP PROXY ERROR: {}", error); + // Build and return the response. + let mut http_response_builder = HttpResponse::Ok(); + if content_type.is_some() { + http_response_builder.content_type(content_type.unwrap()); } - }); + + // Certain resources are replaced. + let replacement_body = match target_url.path().to_lowercase() { + path if path.ends_with("r.css") => Some(R_CSS), + path if path.ends_with("prism.css") => Some(PRISM_CSS), + _ => None, + }; + + // Return the replacement resource or the real resource. + match replacement_body { + Some(body) => http_response_builder.body(body), + None => http_response_builder.body(match response.bytes().await { + Ok(body) => body, + Err(error) => { + println!("Error {:?}", error); + return HttpResponse::BadGateway().finish(); + }, + }), + } + }, + // Error. + Err(error) => { + log::info!("Error proxying {}: {}", target_url, error); + HttpResponse::BadGateway().finish() + }, } } -pub fn start(port: i32) { - spawn!("ark-help-proxy", move || { - match task(port) { - Ok(value) => log::info!("Help proxy server exited with value {:?}", value), - Err(error) => log::error!("Help proxy server exited unexpectedly: {}", error), - } - }); +// Replacement for r.css. +static R_CSS: &'static str = " +body, td { + font-size: var(--vscode-font-size); + font-family: var(--vscode-font-family); + color: var(--vscode-editor-foreground); + background: var(--vscode-editor-background); + line-height: 1.5; +} +body code, +body pre { + color: var(--vscode-editor-foreground); + font-size: var(--vscode-editor-font-size); + font-family: var(--vscode-editor-font-family); + font-weight: var(--vscode-editor-font-weight); +} +a { + color: var(--vscode-textLink-foreground); +} +::selection { + background: var(--vscode-editor-selectionBackground); +} +h1 { + font-size: x-large; +} +h2 { + font-size: x-large; + font-weight: normal; +} +h3 { +} +h4 { + font-style: italic; +} +h5 { +} +h6 { + font-style: italic; +} +img.toplogo { + max-width: 4em; + vertical-align: middle; +} +img.arrow { + width: 30px; + height: 30px; + border: 0; +} +span.acronym { + font-size: small; +} +span.env { + font-size: var(--vscode-editor-font-size); + font-family: var(--vscode-editor-font-family); +} +span.file { + font-size: var(--vscode-editor-font-size); + font-family: var(--vscode-editor-font-family); +} +span.option { + font-size: var(--vscode-editor-font-size); + font-family: var(--vscode-editor-font-family); +} +span.pkg { + font-weight: bold; +} +span.samp { + font-size: var(--vscode-editor-font-size); + font-family: var(--vscode-editor-font-family); +} +table p { + margin-top: 0; + margin-bottom: 6px; + margin-left: 6px; +} +h3.r-arguments-title + table tr td:first-child { + vertical-align: top; + min-width: 24px; + padding-right: 12px; +} +hr { + height: 1.5px; + border: none; + background-color: var(--vscode-textBlockQuote-border); +} +"; + +// Replacement for prism.css. +static PRISM_CSS: &'static str = " +code[class*='language-'], +pre[class*='language-'] { + color: var(--vscode-editor-foreground); + background: none; + text-shadow: none; + font-family: var(--vscode-editor-font-family); + font-size: var(--vscode-editor-font-size); + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.75; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +@media print { + code[class*='language-'], + pre[class*='language-'] { + text-shadow: none; + } +} + +pre[class*='language-'], +:not(pre) > code[class*='language-'] { + /*background: hsl(30, 20%, 25%);*/ +} + +/* Code blocks */ +pre[class*='language-'] { + padding: 1em; + margin: .5em 0; + overflow: auto; + border: 1.5px solid var(--vscode-textBlockQuote-border); + border-radius: .5em; + /*box-shadow: 1px 1px .5em black inset;*/ +} + +/* Inline code */ +:not(pre) > code[class*='language-'] { + padding: .15em .2em .05em; + border-radius: .3em; + border: .13em solid hsl(30, 20%, 40%); + box-shadow: 1px 1px .3em -.1em black inset; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: hsl(30, 20%, 50%); +} + +.token.punctuation { + opacity: .7; +} + +.token.namespace { + opacity: .7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol { + /*color: hsl(350, 40%, 70%);*/ + color: var(--vscode-positronConsole-ansiMagenta); +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + /*color: hsl(75, 70%, 60%);*/ + color: var(--vscode-positronConsole-ansiGreen); +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string, +.token.variable { + /*color: hsl(40, 90%, 60%);*/ + color: var(--vscode-positronConsole-ansiCyan); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + /*color: hsl(350, 40%, 70%);*/ + color: var(--vscode-positronConsole-ansiMagenta); +} + +.token.regex, +.token.important { + /*color: #e90;*/ + color: var(--vscode-positronConsole-ansiBrightYellow); +} + +.token.important, +.token.bold { + font-weight: bold; +} +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +.token.deleted { + color: var(--vscode-positronConsole-ansiRed); } +"; diff --git a/crates/ark/src/modules.rs b/crates/ark/src/modules.rs index 3c393645ce..45c63d8352 100644 --- a/crates/ark/src/modules.rs +++ b/crates/ark/src/modules.rs @@ -6,6 +6,7 @@ // use std::collections::HashMap; +use std::convert::TryFrom; use std::env; use std::path::Path; use std::path::PathBuf; @@ -43,7 +44,7 @@ static mut POSITRON_ATTACHED_ENVIRONMENT: SEXP = std::ptr::null_mut(); pub const POSITRION_ATTACHED_ENVIRONMENT_NAME: &str = "tools:positron"; pub struct RModuleInfo { - pub help_server_port: i32, + pub help_server_port: u16, } // NOTE: We use a custom watcher implementation here to detect changes @@ -205,10 +206,9 @@ pub unsafe fn initialize() -> anyhow::Result { } }); - // Get the help server port. - let help_server_port = RFunction::new("tools", "httpdPort").call()?.to::()?; - - return Ok(RModuleInfo { help_server_port }); + return Ok(RModuleInfo { + help_server_port: u16::try_from(RFunction::new("tools", "httpdPort").call()?.to::()?)?, + }); } pub unsafe fn import(file: &Path) -> anyhow::Result<()> { From 32639174930054d7029fdfb2cfe66036c33a4d05 Mon Sep 17 00:00:00 2001 From: Brian Lambert Date: Tue, 3 Oct 2023 18:07:19 -0700 Subject: [PATCH 2/7] Remove println --- crates/ark/src/help_proxy.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ark/src/help_proxy.rs b/crates/ark/src/help_proxy.rs index ac5d649210..5709a0089b 100644 --- a/crates/ark/src/help_proxy.rs +++ b/crates/ark/src/help_proxy.rs @@ -140,7 +140,7 @@ async fn proxy_request(path: web::Path<(String,)>, app_state: web::Data http_response_builder.body(match response.bytes().await { Ok(body) => body, Err(error) => { - println!("Error {:?}", error); + log::info!("Error proxying {}: {}", target_url_string, error); return HttpResponse::BadGateway().finish(); }, }), From 6c1952396e6e75099b76c9ace226cc3191ec66c2 Mon Sep 17 00:00:00 2001 From: Brian Lambert Date: Tue, 3 Oct 2023 18:08:32 -0700 Subject: [PATCH 3/7] Update log calls --- crates/ark/src/help_proxy.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ark/src/help_proxy.rs b/crates/ark/src/help_proxy.rs index 5709a0089b..ac06ac7c2d 100644 --- a/crates/ark/src/help_proxy.rs +++ b/crates/ark/src/help_proxy.rs @@ -95,7 +95,7 @@ async fn proxy_request(path: web::Path<(String,)>, app_state: web::Data url, Err(error) => { - log::info!("Error proxying {}: {}", target_url_string, error); + log::error!("Error proxying {}: {}", target_url_string, error); return HttpResponse::BadGateway().finish(); }, }; @@ -140,7 +140,7 @@ async fn proxy_request(path: web::Path<(String,)>, app_state: web::Data http_response_builder.body(match response.bytes().await { Ok(body) => body, Err(error) => { - log::info!("Error proxying {}: {}", target_url_string, error); + log::error!("Error proxying {}: {}", target_url_string, error); return HttpResponse::BadGateway().finish(); }, }), @@ -148,7 +148,7 @@ async fn proxy_request(path: web::Path<(String,)>, app_state: web::Data { - log::info!("Error proxying {}: {}", target_url, error); + log::error!("Error proxying {}: {}", target_url, error); HttpResponse::BadGateway().finish() }, } From d3f51e7641d135ca2b0e0415caaf42c7487324a6 Mon Sep 17 00:00:00 2001 From: Brian Lambert Date: Wed, 4 Oct 2023 14:55:35 -0700 Subject: [PATCH 4/7] Add u16 specializations and refactoring such that REALSXP is not allowed for i32 and u16 --- crates/ark/src/browser.rs | 3 +- crates/ark/src/modules.rs | 3 +- crates/harp/src/object.rs | 255 +++++++++++++++++++++++++++++++++++--- 3 files changed, 240 insertions(+), 21 deletions(-) diff --git a/crates/ark/src/browser.rs b/crates/ark/src/browser.rs index 6ade163fa6..61b0e8d615 100644 --- a/crates/ark/src/browser.rs +++ b/crates/ark/src/browser.rs @@ -5,7 +5,6 @@ // // -use std::convert::TryFrom; use std::process::Command; use amalthea::events::PositronEvent; @@ -32,7 +31,7 @@ pub unsafe extern "C" fn ps_browse_url(url: SEXP) -> SEXP { unsafe fn handle_help_url(url: &str) -> Result { // Check for help URLs - let port = u16::try_from(RFunction::new("tools", "httpdPort").call()?.to::()?)?; + let port = RFunction::new("tools", "httpdPort").call()?.to::()?; let prefix = format!("http://127.0.0.1:{}/", port); if !url.starts_with(&prefix) { return Ok(false); diff --git a/crates/ark/src/modules.rs b/crates/ark/src/modules.rs index 45c63d8352..e078db532e 100644 --- a/crates/ark/src/modules.rs +++ b/crates/ark/src/modules.rs @@ -6,7 +6,6 @@ // use std::collections::HashMap; -use std::convert::TryFrom; use std::env; use std::path::Path; use std::path::PathBuf; @@ -207,7 +206,7 @@ pub unsafe fn initialize() -> anyhow::Result { }); return Ok(RModuleInfo { - help_server_port: u16::try_from(RFunction::new("tools", "httpdPort").call()?.to::()?)?, + help_server_port: RFunction::new("tools", "httpdPort").call()?.to::()?, }); } diff --git a/crates/harp/src/object.rs b/crates/harp/src/object.rs index b006109380..34566df4cc 100644 --- a/crates/harp/src/object.rs +++ b/crates/harp/src/object.rs @@ -362,7 +362,6 @@ impl TryFrom for Option { type Error = crate::error::Error; fn try_from(value: RObject) -> Result { unsafe { - let types = &[CHARSXP, STRSXP, SYMSXP]; let charsexp = match r_typeof(*value) { CHARSXP => *value, STRSXP => { @@ -370,7 +369,11 @@ impl TryFrom for Option { STRING_ELT(*value, 0) }, SYMSXP => PRINTNAME(*value), - _ => return Err(Error::UnexpectedType(r_typeof(*value), types.to_vec())), + _ => { + return Err(Error::UnexpectedType(r_typeof(*value), vec![ + CHARSXP, STRSXP, SYMSXP, + ])) + }, }; if charsexp == R_NaString { @@ -383,7 +386,7 @@ impl TryFrom for Option { } } -impl TryFrom for Option { +impl TryFrom for Option { type Error = crate::error::Error; fn try_from(value: RObject) -> Result { unsafe { @@ -391,18 +394,30 @@ impl TryFrom for Option { match r_typeof(*value) { INTSXP => { let x = INTEGER_ELT(*value, 0); - if x == R_NaInt { + if x < u16::MIN as i32 || x > u16::MAX as i32 { Ok(None) } else { - Ok(Some(x)) + Ok(Some(x as u16)) } }, - REALSXP => { - let x = REAL_ELT(*value, 0); - if R_IsNA(x) != 0 { + _ => Err(Error::UnexpectedType(r_typeof(*value), vec![INTSXP])), + } + } + } +} + +impl TryFrom for Option { + type Error = crate::error::Error; + fn try_from(value: RObject) -> Result { + unsafe { + r_assert_length(*value, 1)?; + match r_typeof(*value) { + INTSXP => { + let x = INTEGER_ELT(*value, 0); + if x == R_NaInt { Ok(None) } else { - Ok(Some(x as i32)) + Ok(Some(x)) } }, _ => Err(Error::UnexpectedType(r_typeof(*value), vec![INTSXP])), @@ -459,6 +474,16 @@ impl TryFrom for bool { } } +impl TryFrom for u16 { + type Error = crate::error::Error; + fn try_from(value: RObject) -> Result { + match Option::::try_from(value)? { + Some(x) => Ok(x), + None => Err(Error::MissingValueError), + } + } +} + impl TryFrom for i32 { type Error = crate::error::Error; fn try_from(value: RObject) -> Result { @@ -580,49 +605,245 @@ mod tests { } } + #[test] + #[allow(non_snake_case)] + fn test_tryfrom_RObject_u16() { + r_test! { + // ------------------------------------------------------------------------------------- + // Option::::try_from tests. + // ------------------------------------------------------------------------------------- + + // Test that R_NaInt is None. + assert_match!( + Option::::try_from(RObject::from(R_NaInt)), + Ok(None) => {} + ); + + // Test that below range is None. + assert_match!( + Option::::try_from(RObject::from((u16::MIN as i32) - 1)), + Ok(None) => {} + ); + + // Test that above range is None. + assert_match!( + Option::::try_from(RObject::from((u16::MAX as i32) + 1)), + Ok(None) => {} + ); + + // Test that minimum value is OK. + assert_match!( + Option::::try_from(RObject::from(u16::MIN as i32)), + Ok(Some(x)) => { + assert_eq!(x, u16::MIN) + } + ); + + // Test that maximum value is OK. + assert_match!( + Option::::try_from(RObject::from(u16::MAX as i32)), + Ok(Some(x)) => { + assert_eq!(x, u16::MAX) + } + ); + + // Test that some u16 value is OK. + assert_match!( + Option::::try_from(RObject::from(42)), + Ok(Some(x)) => { + assert_eq!(x, 42) + } + ); + + // Test that R_NaReal is an error. + assert_match!( + Option::::try_from(RObject::from(R_NaReal)), + Err(Error::UnexpectedType(actual_type, expected_types)) => { + assert_eq!(actual_type, REALSXP); + assert_eq!(expected_types, vec![INTSXP]); + } + ); + + // Test that some f64 is an error. + assert_match!( + Option::::try_from(RObject::from(42.0)), + Err(Error::UnexpectedType(actual_type, expected_types)) => { + assert_eq!(actual_type, REALSXP); + assert_eq!(expected_types, vec![INTSXP]); + } + ); + + // ------------------------------------------------------------------------------------- + // u16::try_from tests. + // ------------------------------------------------------------------------------------- + + // Test that R_NaInt is an error. + assert_match!( + u16::try_from(RObject::from(R_NaInt)), + Err(Error::MissingValueError) => {} + ); + + // Test that below range is an error. + assert_match!( + u16::try_from(RObject::from((u16::MIN as i32) - 1)), + Err(Error::MissingValueError) => {} + ); + + // Test that above range is an error. + assert_match!( + u16::try_from(RObject::from((u16::MAX as i32) + 1)), + Err(Error::MissingValueError) => {} + ); + + // Test that minimum value is OK. + assert_match!( + u16::try_from(RObject::from(u16::MIN as i32)), + Ok(x) => { + assert_eq!(x, u16::MIN) + } + ); + + // Test that maximum value is OK. + assert_match!( + u16::try_from(RObject::from(u16::MAX as i32)), + Ok(x) => { + assert_eq!(x, u16::MAX) + } + ); + + // Test that some u16 value is OK. + assert_match!( + u16::try_from(RObject::from(42)), + Ok(x) => { + assert_eq!(x, 42) + } + ); + + // Test that R_NaReal is an error. + assert_match!( + u16::try_from(RObject::from(R_NaReal)), + Err(Error::UnexpectedType(actual_type, expected_types)) => { + assert_eq!(actual_type, REALSXP); + assert_eq!(expected_types, vec![INTSXP]); + } + ); + + // Test that some f64 value is an error. + assert_match!( + u16::try_from(RObject::from(42.0)), + Err(Error::UnexpectedType(actual_type, expected_types)) => { + assert_eq!(actual_type, REALSXP); + assert_eq!(expected_types, vec![INTSXP]); + } + ); + } + } + #[test] #[allow(non_snake_case)] fn test_tryfrom_RObject_i32() { r_test! { + // ------------------------------------------------------------------------------------- + // Option::::try_from tests. + // ------------------------------------------------------------------------------------- + + // Test that R_NaInt is None. assert_match!( Option::::try_from(RObject::from(R_NaInt)), Ok(None) => {} ); + + // Test that minimum value is OK. assert_match!( - Option::::try_from(RObject::from(R_NaReal)), - Ok(None) => {} + Option::::try_from(RObject::from(i32::MIN + 1)), + Ok(Some(x)) => { + assert_eq!(x, i32::MIN + 1) + } + ); + + // Test that maximum value is OK. + assert_match!( + Option::::try_from(RObject::from(i32::MAX)), + Ok(Some(x)) => { + assert_eq!(x, i32::MAX) + } ); + + // Test that some i32 value is OK. assert_match!( Option::::try_from(RObject::from(42)), Ok(Some(x)) => { assert_eq!(x, 42) } ); + + // Test that R_NaReal is an error. + assert_match!( + Option::::try_from(RObject::from(R_NaReal)), + Err(Error::UnexpectedType(actual_type, expected_types)) => { + assert_eq!(actual_type, REALSXP); + assert_eq!(expected_types, vec![INTSXP]); + } + ); + + // Test that some f64 value is an error. assert_match!( Option::::try_from(RObject::from(42.0)), - Ok(Some(x)) => { - assert_eq!(x, 42) + Err(Error::UnexpectedType(actual_type, expected_types)) => { + assert_eq!(actual_type, REALSXP); + assert_eq!(expected_types, vec![INTSXP]); } ); + // ------------------------------------------------------------------------------------- + // i32::try_from tests. + // ------------------------------------------------------------------------------------- + + // Test that R_NaInt is an error. assert_match!( i32::try_from(RObject::from(R_NaInt)), Err(Error::MissingValueError) => {} ); + + // Test that minimum value is OK. assert_match!( - i32::try_from(RObject::from(R_NaReal)), - Err(Error::MissingValueError) => {} + i32::try_from(RObject::from(i32::MIN + 1)), + Ok(x) => { + assert_eq!(x, i32::MIN + 1) + } + ); + + // Test that maximum value is OK. + assert_match!( + i32::try_from(RObject::from(i32::MAX)), + Ok(x) => { + assert_eq!(x, i32::MAX) + } ); + + // Test that some i32 value is OK. assert_match!( i32::try_from(RObject::from(42)), Ok(x) => { assert_eq!(x, 42) } ); + + // Test that R_NaReal is an error. + assert_match!( + i32::try_from(RObject::from(R_NaReal)), + Err(Error::UnexpectedType(actual_type, expected_types)) => { + assert_eq!(actual_type, REALSXP); + assert_eq!(expected_types, vec![INTSXP]); + } + ); + + // Test that some f64 value is an error. assert_match!( i32::try_from(RObject::from(42.0)), - Ok(x) => { - assert_eq!(x, 42) + Err(Error::UnexpectedType(actual_type, expected_types)) => { + assert_eq!(actual_type, REALSXP); + assert_eq!(expected_types, vec![INTSXP]); } ); } From 3ff667cab2b630af0e74d21a51e95a6fb4b893fe Mon Sep 17 00:00:00 2001 From: Brian Lambert Date: Wed, 4 Oct 2023 15:28:02 -0700 Subject: [PATCH 5/7] Use rust-embed to embed R.css and prism.css files instead of hard coding them as strings --- Cargo.lock | 35 +++++ crates/ark/Cargo.toml | 1 + crates/ark/src/help_proxy.rs | 237 ++--------------------------- crates/ark/src/resources/R.css | 90 +++++++++++ crates/ark/src/resources/prism.css | 135 ++++++++++++++++ 5 files changed, 274 insertions(+), 224 deletions(-) create mode 100644 crates/ark/src/resources/R.css create mode 100644 crates/ark/src/resources/prism.css diff --git a/Cargo.lock b/Cargo.lock index e44b2ebaf3..6d695bd83a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -322,6 +322,7 @@ dependencies = [ "regex", "reqwest", "ropey", + "rust-embed", "scraper", "serde", "serde_json", @@ -2327,6 +2328,40 @@ dependencies = [ "str_indices", ] +[[package]] +name = "rust-embed" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e7d90385b59f0a6bf3d3b757f3ca4ece2048265d70db20a2016043d4509a40" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3d8c6fd84090ae348e63a84336b112b5c3918b3bf0493a581f7bd8ee623c29" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn 2.0.29", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "873feff8cb7bf86fdf0a71bb21c95159f4e4a37dd7a4bd1855a940909b583ada" +dependencies = [ + "sha2", + "walkdir", +] + [[package]] name = "rustc-demangle" version = "0.1.23" diff --git a/crates/ark/Cargo.toml b/crates/ark/Cargo.toml index ed925d9237..477e120626 100644 --- a/crates/ark/Cargo.toml +++ b/crates/ark/Cargo.toml @@ -36,6 +36,7 @@ parking_lot = "0.12.1" regex = "1.7.1" reqwest = { version = "0.11.20", features = ["json"] } ropey = "1.6.0" +rust-embed = "8.0.0" scraper = "0.15.0" serde = { version = "1.0.183", features = ["derive"] } serde_json = "1.0.94" diff --git a/crates/ark/src/help_proxy.rs b/crates/ark/src/help_proxy.rs index ac06ac7c2d..b276a016bc 100644 --- a/crates/ark/src/help_proxy.rs +++ b/crates/ark/src/help_proxy.rs @@ -12,11 +12,17 @@ use actix_web::web; use actix_web::App; use actix_web::HttpResponse; use actix_web::HttpServer; +use rust_embed::RustEmbed; use stdext::spawn; use url::Url; use crate::browser; +// Embed src/resources which is where replacement resources can be found. +#[derive(RustEmbed)] +#[folder = "src/resources/"] +struct Asset; + // Starts the help proxy. pub fn start(target_port: u16) { spawn!("ark-help-proxy", move || { @@ -128,15 +134,17 @@ async fn proxy_request(path: web::Path<(String,)>, app_state: web::Data Some(R_CSS), - path if path.ends_with("prism.css") => Some(PRISM_CSS), + let replacement_embedded_file = match target_url.path().to_lowercase() { + path if path.ends_with("r.css") => Asset::get("R.css"), + path if path.ends_with("prism.css") => Asset::get("prism.css"), _ => None, }; // Return the replacement resource or the real resource. - match replacement_body { - Some(body) => http_response_builder.body(body), + match replacement_embedded_file { + Some(replacement_embedded_file) => { + http_response_builder.body(replacement_embedded_file.data) + }, None => http_response_builder.body(match response.bytes().await { Ok(body) => body, Err(error) => { @@ -153,222 +161,3 @@ async fn proxy_request(path: web::Path<(String,)>, app_state: web::Data code[class*='language-'] { + /*background: hsl(30, 20%, 25%);*/ +} + +/* Code blocks */ +pre[class*='language-'] { + padding: 1em; + margin: .5em 0; + overflow: auto; + border: 1.5px solid var(--vscode-textBlockQuote-border); + border-radius: .5em; + /*box-shadow: 1px 1px .5em black inset;*/ +} + +/* Inline code */ +:not(pre) > code[class*='language-'] { + padding: .15em .2em .05em; + border-radius: .3em; + border: .13em solid hsl(30, 20%, 40%); + box-shadow: 1px 1px .3em -.1em black inset; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: hsl(30, 20%, 50%); +} + +.token.punctuation { + opacity: .7; +} + +.token.namespace { + opacity: .7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol { + /*color: hsl(350, 40%, 70%);*/ + color: var(--vscode-positronConsole-ansiMagenta); +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + /*color: hsl(75, 70%, 60%);*/ + color: var(--vscode-positronConsole-ansiGreen); +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string, +.token.variable { + /*color: hsl(40, 90%, 60%);*/ + color: var(--vscode-positronConsole-ansiCyan); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + /*color: hsl(350, 40%, 70%);*/ + color: var(--vscode-positronConsole-ansiMagenta); +} + +.token.regex, +.token.important { + /*color: #e90;*/ + color: var(--vscode-positronConsole-ansiBrightYellow); +} + +.token.important, +.token.bold { + font-weight: bold; +} +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +.token.deleted { + color: var(--vscode-positronConsole-ansiRed); +} From 037d61bf814cb5557403749c773e5b922038bf35 Mon Sep 17 00:00:00 2001 From: Brian Lambert Date: Thu, 5 Oct 2023 10:29:31 -0700 Subject: [PATCH 6/7] Updates to address feedback. It is now an error when a u16 value is out of range. --- crates/harp/src/error.rs | 13 ++++++++ crates/harp/src/object.rs | 70 +++++++++++++++++++++++++++++---------- 2 files changed, 65 insertions(+), 18 deletions(-) diff --git a/crates/harp/src/error.rs b/crates/harp/src/error.rs index 6620094579..8750003b28 100644 --- a/crates/harp/src/error.rs +++ b/crates/harp/src/error.rs @@ -29,6 +29,11 @@ pub enum Error { UnsafeEvaluationError(String), UnexpectedLength(usize, usize), UnexpectedType(u32, Vec), + ValueOutOfRange { + value: i64, + min: i64, + max: i64, + }, InvalidUtf8(Utf8Error), TryCatchError { message: Vec, @@ -107,6 +112,14 @@ impl fmt::Display for Error { ) }, + Error::ValueOutOfRange { value, min, max } => { + write!( + f, + "Value is out of range: value: {} min: {} max: {}", + value, min, max + ) + }, + Error::InvalidUtf8(error) => { write!(f, "Invalid UTF-8 in string: {}", error) }, diff --git a/crates/harp/src/object.rs b/crates/harp/src/object.rs index 34566df4cc..1c51d6a7a7 100644 --- a/crates/harp/src/object.rs +++ b/crates/harp/src/object.rs @@ -394,8 +394,14 @@ impl TryFrom for Option { match r_typeof(*value) { INTSXP => { let x = INTEGER_ELT(*value, 0); - if x < u16::MIN as i32 || x > u16::MAX as i32 { + if x == R_NaInt { Ok(None) + } else if x < u16::MIN as i32 || x > u16::MAX as i32 { + Err(Error::ValueOutOfRange { + value: x as i64, + min: u16::MIN as i64, + max: u16::MAX as i64, + }) } else { Ok(Some(x as u16)) } @@ -619,17 +625,31 @@ mod tests { Ok(None) => {} ); - // Test that below range is None. - assert_match!( - Option::::try_from(RObject::from((u16::MIN as i32) - 1)), - Ok(None) => {} - ); + // Test that below range is as error. + { + let test_value = (u16::MIN as i32) - 1; + assert_match!( + Option::::try_from(RObject::from(test_value)), + Err(Error::ValueOutOfRange { value, min, max }) => { + assert_eq!(value, test_value as i64); + assert_eq!(min, u16::MIN as i64); + assert_eq!(max, u16::MAX as i64); + } + ); + } // Test that above range is None. - assert_match!( - Option::::try_from(RObject::from((u16::MAX as i32) + 1)), - Ok(None) => {} - ); + { + let test_value = (u16::MAX as i32) + 1; + assert_match!( + Option::::try_from(RObject::from(test_value)), + Err(Error::ValueOutOfRange { value, min, max }) => { + assert_eq!(value, test_value as i64); + assert_eq!(min, u16::MIN as i64); + assert_eq!(max, u16::MAX as i64); + } + ); + } // Test that minimum value is OK. assert_match!( @@ -684,16 +704,30 @@ mod tests { ); // Test that below range is an error. - assert_match!( - u16::try_from(RObject::from((u16::MIN as i32) - 1)), - Err(Error::MissingValueError) => {} - ); + { + let test_value = (u16::MIN as i32) - 1; + assert_match!( + u16::try_from(RObject::from((u16::MIN as i32) - 1)), + Err(Error::ValueOutOfRange { value, min, max }) => { + assert_eq!(value, test_value as i64); + assert_eq!(min, u16::MIN as i64); + assert_eq!(max, u16::MAX as i64); + } + ); + } // Test that above range is an error. - assert_match!( - u16::try_from(RObject::from((u16::MAX as i32) + 1)), - Err(Error::MissingValueError) => {} - ); + { + let test_value = (u16::MAX as i32) + 1; + assert_match!( + u16::try_from(RObject::from((u16::MAX as i32) + 1)), + Err(Error::ValueOutOfRange { value, min, max }) => { + assert_eq!(value, test_value as i64); + assert_eq!(min, u16::MIN as i64); + assert_eq!(max, u16::MAX as i64); + } + ); + } // Test that minimum value is OK. assert_match!( From 347af64d3699463571a0adca2333c489c7877511 Mon Sep 17 00:00:00 2001 From: Brian Lambert Date: Thu, 5 Oct 2023 11:38:25 -0700 Subject: [PATCH 7/7] Remove space --- crates/ark/src/resources/prism.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ark/src/resources/prism.css b/crates/ark/src/resources/prism.css index 900f481597..d5d89aee4d 100644 --- a/crates/ark/src/resources/prism.css +++ b/crates/ark/src/resources/prism.css @@ -5,7 +5,7 @@ * */ - code[class*='language-'], +code[class*='language-'], pre[class*='language-'] { color: var(--vscode-editor-foreground); background: none;