diff --git a/.github/workflows/basic-ci.yml b/.github/workflows/basic-ci.yml index 396a299..dfeef6a 100644 --- a/.github/workflows/basic-ci.yml +++ b/.github/workflows/basic-ci.yml @@ -27,7 +27,7 @@ jobs: submodules: true - name: Toolchain (stable with rustfmt, clippy) - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@1.78 with: components: rustfmt, clippy diff --git a/Cargo.lock b/Cargo.lock index 6d05d3b..cf5c02c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,21 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - [[package]] name = "anstream" version = "0.6.21" @@ -155,7 +140,7 @@ dependencies = [ "polling", "rustix", "slab", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -213,7 +198,7 @@ dependencies = [ "rustix", "signal-hook-registry", "slab", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -261,26 +246,11 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "backtrace" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link", -] - [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "blocking" @@ -315,15 +285,15 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "clap" -version = "4.5.48" +version = "4.5.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" +checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" dependencies = [ "clap_builder", "clap_derive", @@ -331,9 +301,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.48" +version = "4.5.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" +checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" dependencies = [ "anstream", "anstyle", @@ -343,21 +313,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.47" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "clap_lex" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "colorchoice" @@ -393,7 +363,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -498,7 +468,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -533,22 +503,16 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.7+wasi-0.2.4", + "wasip2", ] -[[package]] -name = "gimli" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" - [[package]] name = "gloo-timers" version = "0.3.0" @@ -573,22 +537,11 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" -[[package]] -name = "io-uring" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -dependencies = [ - "bitflags", - "cfg-if", - "libc", -] - [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itoa" @@ -617,9 +570,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.176" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "linux-raw-sys" @@ -642,33 +595,15 @@ version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - [[package]] name = "mio" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", -] - -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", + "wasi", + "windows-sys 0.61.2", ] [[package]] @@ -679,9 +614,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "parking" @@ -723,12 +658,12 @@ dependencies = [ "hermit-abi", "pin-project-lite", "rustix", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] name = "presenceforge" -version = "0.1.0-dev" +version = "0.1.0" dependencies = [ "async-std", "blocking", @@ -748,9 +683,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -770,12 +705,6 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - [[package]] name = "rustix" version = "1.1.2" @@ -786,7 +715,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -828,7 +757,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -878,12 +807,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -905,9 +834,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote", @@ -931,43 +860,40 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "tokio" -version = "1.47.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "pin-project-lite", - "slab", "socket2", "tokio-macros", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" [[package]] name = "utf8parse" @@ -998,15 +924,6 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasi" -version = "0.14.7+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" -dependencies = [ - "wasip2", -] - [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" @@ -1039,7 +956,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "wasm-bindgen-shared", ] @@ -1074,7 +991,7 @@ checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1100,18 +1017,9 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-sys" @@ -1119,146 +1027,82 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.4", + "windows-targets", ] [[package]] name = "windows-sys" -version = "0.61.1" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ "windows-link", ] [[package]] name = "windows-targets" -version = "0.52.6" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ "windows-link", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "wit-bindgen" diff --git a/Cargo.toml b/Cargo.toml index 122f165..5562a3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "presenceforge" -version = "0.1.0-dev" -edition = "2024" +version = "0.1.0" +edition = "2021" authors = ["Sreehari Anil "] description = "A library for Discord Rich Presence (IPC) integration" readme = "README.md" @@ -9,6 +9,7 @@ repository = "https://github.com/Sreehari425/presenceforge" license = "MIT OR Apache-2.0" keywords = ["discord", "rpc", "rich-presence", "ipc", "gaming"] categories = ["api-bindings", "games"] +rust-version = "1.78.0" # Configuration for docs.rs to build documentation with all features [package.metadata.docs.rs] @@ -20,7 +21,7 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" byteorder = "1" bytes = "1" -uuid = { version = "1.11", features = ["v4"] } +uuid = { version = "1", features = ["v4"] } futures = { version = "0.3", optional = true } # Async runtime dependencies diff --git a/README.md b/README.md index 3ae053e..950b636 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,10 @@ A Rust library for Discord Rich Presence that actually works without the headach [![Rust](https://img.shields.io/badge/rust-1.70+-blue.svg)](https://www.rust-lang.org) ![Crates.io Version](https://img.shields.io/crates/v/presenceforge) -> **Note**: This is currently in development (v0.1.0-dev). Things might break +> **Note**: This is currently in development (v0.1.0). Things might break. > This is a learning/hobby project. > Features and APIs may change in future versions. - ## Documentation - [Getting Started Guide](docs/GETTING_STARTED.md) - Installation and first steps @@ -27,7 +26,7 @@ A Rust library for Discord Rich Presence that actually works without the headach ## What Works - [x] Linux and macOS (Unix domain sockets) -- [x] Windows support (named pipes) +- [x] Windows support (named pipes) - [x] Flatpak Discord support (automatic detection) - [x] Basic Rich Presence activities - [x] Activity builder pattern @@ -42,21 +41,20 @@ Add PresenceForge to your `Cargo.toml`: ```toml [dependencies] -presenceforge = "0.1.0-dev" +presenceforge = "0.1.0" ``` For async support, add one of the runtime features: ```toml [dependencies] -presenceforge = { version = "0.1.0-dev", features = ["tokio-runtime"] } +presenceforge = { version = "0.1.0", features = ["tokio-runtime"] } # OR -presenceforge = { version = "0.1.0-dev", features = ["async-std-runtime"] } +presenceforge = { version = "0.1.0", features = ["async-std-runtime"] } # OR -presenceforge = { version = "0.1.0-dev", features = ["smol-runtime"] } +presenceforge = { version = "0.1.0", features = ["smol-runtime"] } ``` - ### Basic Usage (Synchronous) ```rust @@ -166,42 +164,6 @@ fn main() -> Result { } ``` -## Examples - -### Game Integration - -```rust -use presenceforge::ActivityBuilder; -use presenceforge::sync::DiscordIpcClient; -let activity = ActivityBuilder::new() - .state("Forest Level") - .details("Fighting goblins") - .start_timestamp_now() - .large_image("forest_map") - .large_text("Enchanted Forest") - .small_image("player_avatar") - .small_text("Level 25 Warrior") - .button("Play Now", "https://your-game.com") - .button("Leaderboard", "https://your-game.com/leaderboard") - .build(); - -client.set_activity(&activity)?; -``` - -### Developer Tools - -```rust -let activity = ActivityBuilder::new() - .state("Writing Rust code") - .details("Building Discord RPC library") - .start_timestamp_now() - .large_image("rust_logo") - .large_text("Rust Programming") - .small_image("vscode") - .small_text("VS Code") - .button("View on GitHub", "https://github.com/your-username/repo") - .build(); -``` ## Getting Your Discord Application ID diff --git a/changelogs/0.1.0.md b/changelogs/0.1.0.md new file mode 100644 index 0000000..74d5b8d --- /dev/null +++ b/changelogs/0.1.0.md @@ -0,0 +1,39 @@ + +## [0.1.0] - release + +### Added + +#### Core Features + +- Cross-platform Discord IPC support (Unix sockets for Linux/macOS, named pipes for Windows) +- Automatic discovery of Discord IPC pipes/sockets +- Flatpak Discord support with automatic detection +- Synchronous client API (`DiscordIpcClient`) +- Unified async API (`AsyncDiscordIpcClient`) with runtime-agnostic design +- Support for Tokio, async-std, and smol runtimes via feature flags +- Activity builder pattern for creating Rich Presence activities +- Full Discord Rich Presence field support (state, details, timestamps, assets, buttons, party) +- Basic input validation for all Discord field length limits +- Pipe discovery and custom path selection +- Connection timeout configuration +- Retry logic with exponential backoff (sync and async) +- Comprehensive error handling with categorization +- UUID v4-based cryptographic nonces for request tracking + +#### Fixes + +- Added checks to enforce that buttons and secrets cannot both be present on the same Activity. This prevents ambiguous configurations where interactive buttons and join/spectate secrets would conflict. + +#### Testing + +- Unit tests for core functionality +- Integration tests for activity builder, serialization, error handling, IPC protocol, and retry logic + +### Feature Flags + +- `tokio-runtime` - Tokio async runtime support +- `async-std-runtime` - async-std runtime support +- `smol-runtime` - smol runtime support +- `secrets` - add basic secrets supports (experimental) +### Notes +- Rust edition updated to 2021, reducing minimum supported Rust version (MSRV) to 1.78.0 diff --git a/docs/ACTIVITY_BUILDER_REFERENCE.md b/docs/ACTIVITY_BUILDER_REFERENCE.md index 9abc6af..afa47af 100644 --- a/docs/ACTIVITY_BUILDER_REFERENCE.md +++ b/docs/ACTIVITY_BUILDER_REFERENCE.md @@ -2,7 +2,7 @@ This document explains every field available in the ActivityBuilder and how it appears in Discord. -> ⚠️ **NOTE:** This feature is experimental/untested. Use at your own risk. +> ⚠️ **NOTE:** There are features which are experimental/untested. Use at your own risk. ## Visual Layout @@ -174,7 +174,7 @@ let end_time = now + 300; ### 8. **Secrets** (For "Ask to Join" and Spectate features) > **⚠️ Feature Flag Required:** These methods require the `secrets` feature flag to be enabled. -> Add to your `Cargo.toml`: `presenceforge = { version = "0.1.0-dev", features = ["secrets"] }` +> Add to your `Cargo.toml`: `presenceforge = { version = "0.1.0", features = ["secrets"] }` #### Note: untested feature diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md index 9b21881..6d2bec8 100644 --- a/docs/API_REFERENCE.md +++ b/docs/API_REFERENCE.md @@ -2,7 +2,7 @@ API reference for PresenceForge (work-in-progress; APIs may change). -> **Note:** PresenceForge v0.1.0-dev is an early development release. +> **Note:** PresenceForge v0.1.0 is an early development release. > It’s functional, but features may change or be incomplete. ## Table of Contents diff --git a/docs/ASYNC_RUNTIMES.md b/docs/ASYNC_RUNTIMES.md index 739f5b5..e9d12c0 100644 --- a/docs/ASYNC_RUNTIMES.md +++ b/docs/ASYNC_RUNTIMES.md @@ -1,6 +1,6 @@ # Async Runtimes Guide -> **Note:** PresenceForge v0.1.0-dev is an early development release. +> **Note:** PresenceForge v0.1.0 is an early development release. > It’s functional, but features may change or be incomplete. ## Table of Contents @@ -63,13 +63,13 @@ Add to your `Cargo.toml` with **one** of these feature flags: ```toml [dependencies] # For Tokio -presenceforge = { version = "0.1.0-dev", features = ["tokio-runtime"] } +presenceforge = { version = "0.1.0", features = ["tokio-runtime"] } # For async-std -presenceforge = { version = "0.1.0-dev", features = ["async-std-runtime"] } +presenceforge = { version = "0.1.0", features = ["async-std-runtime"] } # For smol -presenceforge = { version = "0.1.0-dev", features = ["smol-runtime"] } +presenceforge = { version = "0.1.0", features = ["smol-runtime"] } ``` **This exact code works with all three runtimes:** @@ -140,7 +140,7 @@ Add to your `Cargo.toml`: ```toml [dependencies] -presenceforge = { version = "0.1.0-dev", features = ["tokio-runtime"] } +presenceforge = { version = "0.1.0", features = ["tokio-runtime"] } tokio = { version = "1", features = ["rt-multi-thread", "macros"] } ``` @@ -320,7 +320,7 @@ async-std provides an async API similar to the standard library. ```toml [dependencies] -presenceforge = { version = "0.1.0-dev", features = ["async-std-runtime"] } +presenceforge = { version = "0.1.0", features = ["async-std-runtime"] } async-std = { version = "1", features = ["attributes"] } ``` @@ -419,7 +419,7 @@ smol is a small and fast async runtime. ```toml [dependencies] -presenceforge = { version = "0.1.0-dev", features = ["smol-runtime"] } +presenceforge = { version = "0.1.0", features = ["smol-runtime"] } smol = "2" ``` diff --git a/docs/ERROR_HANDLING.md b/docs/ERROR_HANDLING.md index fa8cb78..7162b7d 100644 --- a/docs/ERROR_HANDLING.md +++ b/docs/ERROR_HANDLING.md @@ -25,7 +25,7 @@ PresenceForge uses the `DiscordIpcError` enum for all error cases. All fallible use presenceforge::Result; use presenceforge::sync::DiscordIpcClient; -fn main() -> Result<(), Box> { +fn main() -> Result<()> { let mut client = DiscordIpcClient::new("your_client_id")?; client.connect()?; @@ -178,8 +178,8 @@ match category { ```rust if error.is_connection_error() { - eprintln!("💡 Tip: Make sure Discord is running!"); - eprintln!("💡 Try: ps aux | grep -i discord"); + eprintln!(" Tip: Make sure Discord is running!"); + eprintln!(" Try: ps aux | grep -i discord"); } ``` @@ -187,7 +187,7 @@ if error.is_connection_error() { ```rust if error.is_recoverable() { - println!("♻️ This error might be recoverable - trying again..."); + println!(" This error might be recoverable - trying again..."); retry_logic(); } else { eprintln!(" Fatal error - cannot continue"); @@ -215,8 +215,8 @@ fn connect_to_discord(client_id: &str) -> Result { eprintln!(" Cannot connect to Discord"); - eprintln!("🔍 Make sure Discord is running"); - eprintln!("💡 Start Discord and try again"); + eprintln!(" Make sure Discord is running"); + eprintln!(" Start Discord and try again"); Err("Discord not running".into()) } Err(e) => Err(e.into()), @@ -248,7 +248,7 @@ fn maintain_presence(mut client: DiscordIpcClient) -> Result<(), Box { - eprintln!("⚠️ Connection lost. Recreating client and reconnecting..."); + eprintln!(" Connection lost. Recreating client and reconnecting..."); // Recreate the client (sync API has no reconnect method) client = DiscordIpcClient::new("your_client_id")?; let _ = client.connect()?; @@ -445,15 +445,15 @@ fn setup_client() -> Result> { // Get client ID from environment let client_id = env::var("DISCORD_CLIENT_ID").map_err(|_| { eprintln!(" DISCORD_CLIENT_ID environment variable not set"); - eprintln!("💡 Set it with: export DISCORD_CLIENT_ID='your_app_id'"); - eprintln!("💡 Get your App ID from: https://discord.com/developers/applications"); + eprintln!(" Set it with: export DISCORD_CLIENT_ID='your_app_id'"); + eprintln!(" Get your App ID from: https://discord.com/developers/applications"); "Missing DISCORD_CLIENT_ID" })?; // Validate client ID format (should be numeric) if !client_id.chars().all(|c| c.is_numeric()) { eprintln!(" Invalid client ID format: {}", client_id); - eprintln!("💡 Client ID should be a numeric string"); + eprintln!(" Client ID should be a numeric string"); return Err("Invalid client ID format".into()); } @@ -462,7 +462,7 @@ fn setup_client() -> Result> { Ok(c) => c, Err(DiscordIpcError::InvalidClientId) => { eprintln!(" Discord rejected client ID: {}", client_id); - eprintln!("💡 Verify this is the correct Application ID"); + eprintln!(" Verify this is the correct Application ID"); return Err("Invalid client ID".into()); } Err(e) => return Err(e.into()), @@ -688,8 +688,8 @@ fn update_presence_best_effort( match client.set_activity(activity) { Ok(_) => println!(" Presence updated"), Err(e) => { - eprintln!("⚠️ Failed to update presence: {}", e); - eprintln!("💡 Continuing without Rich Presence"); + eprintln!(" Failed to update presence: {}", e); + eprintln!(" Continuing without Rich Presence"); // Application continues without Rich Presence } } @@ -704,7 +704,7 @@ fn update_presence_best_effort( fn connect_with_user_feedback( client_id: &str ) -> Result> { - println!("🔄 Connecting to Discord..."); + println!(" Connecting to Discord..."); match DiscordIpcClient::new(client_id) { Ok(mut client) => { @@ -715,7 +715,7 @@ fn connect_with_user_feedback( } Err(e) => { eprintln!(" Handshake failed: {}", e); - eprintln!("💡 Try restarting Discord"); + eprintln!(" Try restarting Discord"); Err(e.into()) } } @@ -723,7 +723,7 @@ fn connect_with_user_feedback( Err(e) => { eprintln!(" Connection failed: {}", e); eprintln!(); - eprintln!("🔍 Troubleshooting checklist:"); + eprintln!(" Troubleshooting checklist:"); eprintln!(" [ ] Discord is installed"); eprintln!(" [ ] Discord is running"); eprintln!(" [ ] Discord is not blocked by firewall"); diff --git a/docs/FAQ.md b/docs/FAQ.md index f4aa201..e57a8a4 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -52,11 +52,11 @@ git ls-remote git@github.com:Sreehari425/presenceforge.git If SSH works but you still have issues, please report them on GitHub Issues. -For now, use version `0.1.0-dev` instead: +For now, use version `0.1.0` instead: ```toml [dependencies] -presenceforge = "0.1.0-dev" +presenceforge = "0.1.0" ``` --- @@ -74,7 +74,7 @@ The feature is called `tokio-runtime`, not `tokio`: ```toml [dependencies] -presenceforge = { version = "0.1.0-dev", features = ["tokio-runtime"] } +presenceforge = { version = "0.1.0", features = ["tokio-runtime"] } ``` Valid features: `tokio-runtime`, `async-std-runtime`, `smol-runtime` @@ -94,7 +94,7 @@ Make sure you're using compatible versions: ```toml [dependencies] -presenceforge = { version = "0.1.0-dev", features = ["tokio-runtime"] } +presenceforge = { version = "0.1.0", features = ["tokio-runtime"] } tokio = { version = "1", features = ["full"] } # Use version 1.x ``` diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index 0bf0ff5..227f77c 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -2,7 +2,7 @@ Welcome to PresenceForge! This guide will help you get started with integrating Discord Rich Presence into your Rust application. -> **Note:** PresenceForge v0.1.0-dev is an early development release. +> **Note:** PresenceForge v0.1.0 is an early development release. > It’s functional, but features may change or be incomplete. ## What is Discord Rich Presence? @@ -36,7 +36,7 @@ Add PresenceForge to your `Cargo.toml`: ```toml [dependencies] -presenceforge = "0.1.0-dev" +presenceforge = "0.1.0" ``` ### With Async Support @@ -46,13 +46,13 @@ If you need async support, add one of the runtime features: ```toml [dependencies] # For Tokio users -presenceforge = { version = "0.1.0-dev", features = ["tokio-runtime"] } +presenceforge = { version = "0.1.0", features = ["tokio-runtime"] } # For async-std users -presenceforge = { version = "0.1.0-dev", features = ["async-std-runtime"] } +presenceforge = { version = "0.1.0", features = ["async-std-runtime"] } # For smol users -presenceforge = { version = "0.1.0-dev", features = ["smol-runtime"] } +presenceforge = { version = "0.1.0", features = ["smol-runtime"] } ``` ## Your First Rich Presence @@ -70,7 +70,7 @@ cd my-discord-presence ```toml [dependencies] -presenceforge = "0.1.0-dev" +presenceforge = "0.1.0" ``` ### Step 3: Write your first presence diff --git a/docs/PIPE_SELECTION.md b/docs/PIPE_SELECTION.md index 1ea8b1f..90817d7 100644 --- a/docs/PIPE_SELECTION.md +++ b/docs/PIPE_SELECTION.md @@ -4,7 +4,7 @@ This document describes the pipe selection and discovery features in PresenceForge, giving developers control over which Discord IPC pipe to connect to. -> ⚠️ **NOTE:** This feature is experimental/untested. Use at your own risk. +> ⚠️ **NOTE:** This feature is experimental. Use at your own risk. ## Key Features diff --git a/examples/async_tokio_reconnect.rs b/examples/async_tokio_reconnect.rs index 5a10e4b..c4cced2 100644 --- a/examples/async_tokio_reconnect.rs +++ b/examples/async_tokio_reconnect.rs @@ -1,9 +1,9 @@ #[cfg(feature = "tokio-runtime")] mod tokio_example { use clap::Parser; - use presenceforge::retry::{RetryConfig, with_retry_async}; + use presenceforge::retry::{with_retry_async, RetryConfig}; use presenceforge::{ActivityBuilder, AsyncDiscordIpcClient, Result}; - use tokio::time::{Duration, sleep}; + use tokio::time::{sleep, Duration}; /// Discord Rich Presence Async Tokio Reconnection Example #[derive(Parser, Debug)] diff --git a/examples/basic.rs b/examples/basic.rs index 9d35f3a..cf06467 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -30,7 +30,7 @@ fn main() -> Result { std::process::exit(1); }); - let mut client = DiscordIpcClient::new(&client_id)?; + let mut client = DiscordIpcClient::new(client_id)?; // Perform handshake client.connect()?; diff --git a/examples/builder_all.rs b/examples/builder_all.rs index 8387efe..c73cbc4 100644 --- a/examples/builder_all.rs +++ b/examples/builder_all.rs @@ -37,7 +37,7 @@ fn main() -> Result { println!("=== Complete ActivityBuilder Reference Example ===\n"); - let mut client = DiscordIpcClient::new(&client_id)?; + let mut client = DiscordIpcClient::new(client_id)?; // Perform handshake println!("Connecting to Discord..."); @@ -47,7 +47,7 @@ fn main() -> Result { // Create an activity with ALL possible fields println!("Setting activity with all available options...\n"); - let activity = ActivityBuilder::new() + let mut builder = ActivityBuilder::new() // ═══════════════════════════════════════════════════════════ // BASIC TEXT FIELDS // ═══════════════════════════════════════════════════════════ @@ -62,7 +62,6 @@ fn main() -> Result { // ═══════════════════════════════════════════════════════════ // Start timestamp: Shows "elapsed" time (e.g., "00:15 elapsed") // Use .start_timestamp_now() for current time - .start_timestamp_now()? // End timestamp: Shows "remaining" time (e.g., "02:30 left") // Note: If you set both start and end, Discord shows remaining time // Uncomment to try: @@ -88,35 +87,44 @@ fn main() -> Result { // Useful for multiplayer games showing current players // Parameters: party_id, current_size, max_size .party("party-12345", 2, 4) - // ═══════════════════════════════════════════════════════════ - // BUTTONS (Clickable buttons - max 2) - // ═══════════════════════════════════════════════════════════ - // Button 1: First clickable button - // Parameters: label (button text), url (where it goes) - .button(" View Game", "https://example.com/game") - // Button 2: Second clickable button - // Note: Discord only allows up to 2 buttons - .button(" Documentation", "https://docs.rs/presenceforge") + // NOTE : BUTTONS and SECRETS are mutually exclusive. We add buttons + // only when the `secrets` feature is NOT enabled so the example + // remains valid in both configurations. // ═══════════════════════════════════════════════════════════ // SECRETS (For "Ask to Join" and spectate features) // ═══════════════════════════════════════════════════════════ - // NOTE: Secret methods require the 'secrets' feature flag - // Uncomment and enable the feature to use these: - // - // #[cfg(feature = "secrets")] - // .join_secret("join_secret_12345") - // #[cfg(feature = "secrets")] - // .spectate_secret("spectate_secret_67890") - // #[cfg(feature = "secrets")] - // .match_secret("match_secret_abcde") + // NOTE: Secret methods require the 'secrets' feature flag. + // To enable, run the example with `--features secrets`. + // The secret methods are only compiled when the feature is enabled, + // so we call them inside a cfg block below. // ═══════════════════════════════════════════════════════════ // INSTANCE (Boolean flag) // ═══════════════════════════════════════════════════════════ // Instance: Whether this is an instanced context (like a match) // Set to true for unique game instances, false for general activities - .instance(true) - // Build the activity - .build(); + .instance(true); + // Apply the start timestamp (this can fail if system time is invalid) + builder = builder.start_timestamp_now()?; + + // Conditionally add buttons when the secrets feature is NOT enabled + #[cfg(not(feature = "secrets"))] + { + builder = builder + .button("View Game", "https://example.com/game") + .button("Documentation", "https://docs.rs/presenceforge"); + } + + // Conditionally add secrets when feature is enabled + #[cfg(feature = "secrets")] + { + builder = builder + .join_secret("join_secret_12345") + .spectate_secret("spectate_secret_67890") + .match_secret("match_secret_abcde"); + } + + // Build the activity + let activity = builder.build(); // Set the activity // println!("{activity:?}"); @@ -129,7 +137,10 @@ fn main() -> Result { println!(" • Large image with tooltip"); println!(" • Small image (Rust logo) in corner"); println!(" • Party info: '2 of 4'"); + #[cfg(not(feature = "secrets"))] println!(" • Two clickable buttons"); + #[cfg(feature = "secrets")] + println!(" • Join/spectate/match secrets enabled (ask-to-join)"); println!(" • Elapsed time counter"); // Keep activity visible for 30 seconds @@ -158,7 +169,10 @@ fn main() -> Result { println!("│ Party: 2 of 4 │"); println!("│ ⏱ 00:15 elapsed │"); println!("│ │"); + #[cfg(not(feature = "secrets"))] println!("│ [Button 1] [Button 2] │"); + #[cfg(feature = "secrets")] + println!("│ [Secrets] │"); println!("└─────────────────────────────────────────┘"); println!(); println!("💡 Tips:"); diff --git a/examples/coding_status.rs b/examples/coding_status.rs index 3e57e44..8b581c0 100644 --- a/examples/coding_status.rs +++ b/examples/coding_status.rs @@ -33,7 +33,7 @@ fn main() -> Result { std::process::exit(1); }); - let mut client = DiscordIpcClient::new(&client_id)?; + let mut client = DiscordIpcClient::new(client_id)?; println!(" Starting Discord Rich Presence for Codings"); client.connect()?; diff --git a/examples/connection_retry.rs b/examples/connection_retry.rs index ec08f36..9cd438b 100644 --- a/examples/connection_retry.rs +++ b/examples/connection_retry.rs @@ -1,5 +1,5 @@ use clap::Parser; -use presenceforge::retry::{RetryConfig, with_retry}; +use presenceforge::retry::{with_retry, RetryConfig}; use presenceforge::sync::DiscordIpcClient; use presenceforge::{ActivityBuilder, Result}; use std::time::Duration; diff --git a/examples/custom_activity.rs b/examples/custom_activity.rs index 6522933..ea66fc3 100644 --- a/examples/custom_activity.rs +++ b/examples/custom_activity.rs @@ -36,7 +36,7 @@ fn main() -> Result { std::process::exit(1); }); - let mut client = DiscordIpcClient::new(&client_id)?; + let mut client = DiscordIpcClient::new(client_id)?; println!(" Creating custom activity manually"); client.connect()?; diff --git a/examples/game_demo.rs b/examples/game_demo.rs index c1dc759..c8c254a 100644 --- a/examples/game_demo.rs +++ b/examples/game_demo.rs @@ -31,7 +31,7 @@ fn main() -> Result { std::process::exit(1); }); - let mut client = DiscordIpcClient::new(&client_id)?; + let mut client = DiscordIpcClient::new(client_id)?; println!("🎮 Starting Discord Rich Presence for Game Demo..."); client.connect()?; diff --git a/examples/pipe_selection.rs b/examples/pipe_selection.rs index 0f74ce2..5aa6e23 100644 --- a/examples/pipe_selection.rs +++ b/examples/pipe_selection.rs @@ -98,7 +98,7 @@ fn main() -> Result<(), Box> { let custom_path = pipes[0].path.clone(); println!("4. Connecting using custom path: {}...", custom_path); let mut client3 = DiscordIpcClient::new_with_config( - "your_client_id", + &client_id, Some(PipeConfig::CustomPath(custom_path.clone())), )?; client3.connect()?; @@ -118,7 +118,7 @@ fn main() -> Result<(), Box> { pipe_num, pipe_path ); let mut client4 = DiscordIpcClient::new_with_config_and_timeout( - "your_client_id", + &client_id, Some(PipeConfig::CustomPath(pipe_path)), 5000, )?; diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..098f812 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.78.0" +components = ["rustfmt", "clippy", "rust-src"] diff --git a/scripts/check_clippy.sh b/scripts/check_clippy.sh old mode 100644 new mode 100755 diff --git a/scripts/check_fmt.sh b/scripts/check_fmt.sh old mode 100644 new mode 100755 diff --git a/scripts/count_rust_loc.sh b/scripts/count_rust_loc.sh old mode 100644 new mode 100755 diff --git a/scripts/list_rust_files.sh b/scripts/list_rust_files.sh old mode 100644 new mode 100755 index eee36e3..3985f3d --- a/scripts/list_rust_files.sh +++ b/scripts/list_rust_files.sh @@ -4,4 +4,3 @@ find .. -type f -name '*.rs' \ -not -path '../target/*' \ -not -path '../scripts/*' \ -not -path '../docs/*' \ - -not -path '../.history/' diff --git a/src/activity/types.rs b/src/activity/types.rs index 6be7dda..c148573 100644 --- a/src/activity/types.rs +++ b/src/activity/types.rs @@ -74,6 +74,24 @@ impl Activity { } } + // Buttons and secrets are mutually exclusive. If any secret field is set, + // the activity MUST NOT contain interactive buttons. We only consider + // secrets "present" when at least one of the inner secret fields is + // Some(...). An Option that exists but contains no + // secrets is considered empty and does not conflict with buttons. + #[cfg(feature = "secrets")] + { + if self.buttons.is_some() + && self + .secrets + .as_ref() + .map(|s| s.join.is_some() || s.spectate.is_some() || s.match_secret.is_some()) + .unwrap_or(false) + { + return Err("Buttons and secrets cannot coexist in the same Activity".to_string()); + } + } + // Validate asset keys if let Some(assets) = &self.assets { if let Some(large_image) = &assets.large_image { @@ -265,4 +283,25 @@ mod tests { let error = activity.validate().unwrap_err(); assert!(error.contains("Current party size")); } + + #[test] + #[cfg(feature = "secrets")] + fn buttons_and_secrets_cannot_coexist() { + // Build an activity that contains both a button and a secret and + // ensure validate() rejects it. + let activity = Activity { + buttons: Some(vec![ActivityButton { + label: "Join".to_string(), + url: "https://example.com/join".to_string(), + }]), + secrets: Some(ActivitySecrets { + join: Some("secret".to_string()), + ..ActivitySecrets::default() + }), + ..Default::default() + }; + + let err = activity.validate().unwrap_err(); + assert!(err.contains("Buttons and secrets cannot coexist")); + } } diff --git a/src/async_io/async_std/mod.rs b/src/async_io/async_std/mod.rs index 3012ee4..4da95b8 100644 --- a/src/async_io/async_std/mod.rs +++ b/src/async_io/async_std/mod.rs @@ -21,7 +21,7 @@ use std::sync::{Arc, Mutex}; use crate::async_io::traits::{AsyncRead, AsyncWrite}; use crate::debug_println; use crate::error::{DiscordIpcError, Result}; -use crate::ipc::{PipeConfig, constants}; +use crate::ipc::{constants, PipeConfig}; /// A Discord IPC connection using async-std pub(crate) enum AsyncStdConnection { @@ -298,7 +298,15 @@ impl AsyncWrite for AsyncStdConnection { // Use blocking crate to handle synchronous I/O in async context blocking::unblock(move || { - let mut file = pipe_clone.lock().unwrap(); + let mut file = match pipe_clone.lock() { + Ok(f) => f, + Err(e) => { + return Err(io::Error::new( + io::ErrorKind::Other, + format!("Mutex poisoned: {}", e), + )); + } + }; file.write(&data) }) .await @@ -319,7 +327,15 @@ impl AsyncWrite for AsyncStdConnection { let pipe_clone = Arc::clone(pipe); blocking::unblock(move || { - let mut file = pipe_clone.lock().unwrap(); + let mut file = match pipe_clone.lock() { + Ok(f) => f, + Err(e) => { + return Err(io::Error::new( + io::ErrorKind::Other, + format!("Mutex poisoned: {}", e), + )); + } + }; file.flush() }) .await diff --git a/src/async_io/client.rs b/src/async_io/client.rs index 0fd99bd..3944735 100644 --- a/src/async_io/client.rs +++ b/src/async_io/client.rs @@ -3,17 +3,17 @@ #![allow(clippy::collapsible_if)] use bytes::{BufMut, BytesMut}; -use serde_json::{Value, json}; +use serde_json::{json, Value}; use std::collections::VecDeque; use std::process; use std::time::{Duration, Instant}; use super::traits::ipc_utils::read_u32_le; -use super::traits::{AsyncRead, AsyncWrite, read_exact, write_all}; +use super::traits::{read_exact, write_all, AsyncRead, AsyncWrite}; use crate::activity::Activity; use crate::debug_println; use crate::error::{DiscordIpcError, Result}; -use crate::ipc::{Command, HandshakePayload, IpcMessage, Opcode, constants}; +use crate::ipc::{constants, Command, HandshakePayload, IpcMessage, Opcode}; use crate::nonce::generate_nonce; /// Async implementation of Discord IPC client diff --git a/src/async_io/smol/mod.rs b/src/async_io/smol/mod.rs index 0cbb9e7..336c711 100644 --- a/src/async_io/smol/mod.rs +++ b/src/async_io/smol/mod.rs @@ -19,7 +19,7 @@ use std::sync::{Arc, Mutex}; use crate::async_io::traits::{AsyncRead, AsyncWrite}; use crate::debug_println; use crate::error::{DiscordIpcError, Result}; -use crate::ipc::{PipeConfig, constants}; +use crate::ipc::{constants, PipeConfig}; /// A Discord IPC connection using smol pub(crate) enum SmolConnection { @@ -306,7 +306,15 @@ impl AsyncWrite for SmolConnection { // Use smol's unblock to handle synchronous I/O in async context smol::unblock(move || { - let mut file = pipe_clone.lock().unwrap(); + let mut file = match pipe_clone.lock() { + Ok(f) => f, + Err(e) => { + return Err(io::Error::new( + io::ErrorKind::Other, + format!("Mutex poisoned: {}", e), + )); + } + }; file.write(&data) }) .await @@ -327,7 +335,15 @@ impl AsyncWrite for SmolConnection { let pipe_clone = Arc::clone(pipe); smol::unblock(move || { - let mut file = pipe_clone.lock().unwrap(); + let mut file = match pipe_clone.lock() { + Ok(f) => f, + Err(e) => { + return Err(io::Error::new( + io::ErrorKind::Other, + format!("Mutex poisoned: {}", e), + )); + } + }; file.flush() }) .await @@ -447,8 +463,8 @@ pub mod client { /// Performs handshake with Discord with a timeout pub async fn connect_with_timeout(&mut self, timeout_duration: Duration) -> Result { - use smol::Timer; use smol::future::or; + use smol::Timer; match or( async move { @@ -509,8 +525,8 @@ pub mod client { &mut self, timeout_duration: Duration, ) -> impl std::future::Future> + Send { - use smol::Timer; use smol::future::or; + use smol::Timer; async move { match or( diff --git a/src/async_io/tokio/mod.rs b/src/async_io/tokio/mod.rs index e848fc6..0d6ba33 100644 --- a/src/async_io/tokio/mod.rs +++ b/src/async_io/tokio/mod.rs @@ -14,7 +14,7 @@ use tokio::net::windows::named_pipe::{ClientOptions, NamedPipeClient}; use crate::async_io::traits::{AsyncRead, AsyncWrite}; use crate::error::{DiscordIpcError, Result}; -use crate::ipc::{PipeConfig, constants}; +use crate::ipc::{constants, PipeConfig}; /// A Discord IPC connection using Tokio pub(crate) enum TokioConnection { @@ -46,7 +46,7 @@ impl TokioConnection { config: Option, timeout_ms: u64, ) -> Result { - use tokio::time::{Duration, timeout}; + use tokio::time::{timeout, Duration}; let timeout_duration = Duration::from_millis(timeout_ms); diff --git a/src/error.rs b/src/error.rs index dc86180..4f6b43b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -76,7 +76,7 @@ impl Display for ErrorCategory { /// # Error Handling Examples /// /// Basic error handling: -/// ```rust +/// ```rust,no_run /// use presenceforge::DiscordIpcError; /// use presenceforge::sync::DiscordIpcClient; /// fn main() -> Result<(), Box> { diff --git a/src/ipc/connection.rs b/src/ipc/connection.rs index 1eb7eb9..da95470 100644 --- a/src/ipc/connection.rs +++ b/src/ipc/connection.rs @@ -12,7 +12,7 @@ use std::fs::OpenOptions; use std::io::{BufReader, BufWriter}; use crate::error::{DiscordIpcError, ProtocolContext, Result}; -use crate::ipc::protocol::{Opcode, constants}; +use crate::ipc::protocol::{constants, Opcode}; /// Configuration for selecting which Discord IPC pipe to connect to #[derive(Debug, Clone, Default)] @@ -368,8 +368,8 @@ impl IpcConnection { #[cfg(windows)] /// Connect to Discord IPC named pipe on Windows using auto-discovery - fn connect_to_discord_windows_auto() - -> Result<(BufReader, BufWriter)> { + fn connect_to_discord_windows_auto( + ) -> Result<(BufReader, BufWriter)> { let mut last_error = None; let mut attempted_paths = Vec::new(); diff --git a/src/lib.rs b/src/lib.rs index 862b118..ef34dd5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,7 +52,7 @@ //! //! ```toml //! [dependencies] -//! presenceforge = { version = "0.1.0-dev", features = ["tokio-runtime"] } +//! presenceforge = { version = "0.1.0", features = ["tokio-runtime"] } //! tokio = { version = "1", features = ["rt-multi-thread", "macros"] } //! ``` //! @@ -87,7 +87,7 @@ //! //! ```toml //! [dependencies] -//! presenceforge = { version = "0.1.0-dev", features = ["async-std-runtime"] } +//! presenceforge = { version = "0.1.0", features = ["async-std-runtime"] } //! async-std = { version = "1", features = ["attributes"] } //! ``` //! @@ -122,7 +122,7 @@ //! //! ```toml //! [dependencies] -//! presenceforge = { version = "0.1.0-dev", features = ["smol-runtime"] } +//! presenceforge = { version = "0.1.0", features = ["smol-runtime"] } //! smol = "2" //! ``` //! diff --git a/src/sync/client.rs b/src/sync/client.rs index dbcc8fb..01b6254 100644 --- a/src/sync/client.rs +++ b/src/sync/client.rs @@ -1,6 +1,6 @@ #![allow(clippy::collapsible_if)] -use serde_json::{Value, json}; +use serde_json::{json, Value}; use std::collections::VecDeque; use std::process; use std::time::{Duration, Instant}; @@ -9,7 +9,7 @@ use crate::activity::Activity; use crate::debug_println; use crate::error::{DiscordIpcError, Result}; use crate::ipc::{ - Command, HandshakePayload, IpcConnection, IpcMessage, Opcode, PipeConfig, constants, + constants, Command, HandshakePayload, IpcConnection, IpcMessage, Opcode, PipeConfig, }; use crate::nonce::generate_nonce; diff --git a/tests/integration_retry.rs b/tests/integration_retry.rs index fa0cd44..5bc70e8 100644 --- a/tests/integration_retry.rs +++ b/tests/integration_retry.rs @@ -1,7 +1,7 @@ use presenceforge::retry::with_retry; -use presenceforge::{DiscordIpcError, retry::RetryConfig}; -use std::sync::Arc; +use presenceforge::{retry::RetryConfig, DiscordIpcError}; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; fn quick_retry_config(max_attempts: u32) -> RetryConfig { RetryConfig::new(max_attempts, 5, 20, 2.0)