diff --git a/examples/qr-link/.cargo/config.toml b/examples/qr-link/.cargo/config.toml new file mode 100755 index 0000000..6b77899 --- /dev/null +++ b/examples/qr-link/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target = "wasm32-wasi" diff --git a/examples/qr-link/.gitignore b/examples/qr-link/.gitignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/examples/qr-link/.gitignore @@ -0,0 +1 @@ +target diff --git a/examples/qr-link/Cargo.lock b/examples/qr-link/Cargo.lock new file mode 100644 index 0000000..95293e2 --- /dev/null +++ b/examples/qr-link/Cargo.lock @@ -0,0 +1,638 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64-serde" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba368df5de76a5bea49aaf0cf1b39ccfbbef176924d1ba5db3e4135216cbe3c7" +dependencies = [ + "base64 0.21.7", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "bytemuck" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" + +[[package]] +name = "cc" +version = "1.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "extism-convert" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b6253fe1e378abdd0fd9fd01b53aa8757c6827cd3c48794b417e542d088d0e" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bytemuck", + "extism-convert-macros", + "prost", + "rmp-serde", + "serde", + "serde_json", +] + +[[package]] +name = "extism-convert-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7022773c485da2122413c2edbf50b7dee135b6577cc5ac42dccc307e347ac5d6" +dependencies = [ + "manyhow", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "extism-manifest" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cca9129d54add3090148a17444879256b4ec3fd7c4269d2780cd70050232edda" +dependencies = [ + "base64 0.22.1", + "serde", + "serde_json", +] + +[[package]] +name = "extism-pdk" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0334e38735348bd085e518bfc284395fcb5c198ba65ce36f9712bd25ff9e7be0" +dependencies = [ + "anyhow", + "base64 0.22.1", + "extism-convert", + "extism-manifest", + "extism-pdk-derive", + "serde", + "serde_json", +] + +[[package]] +name = "extism-pdk-derive" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4b8ea80a1b89cf8b053bdc5df2385125bcb9110d19be289c2030c61c7c6ad9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "manyhow" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587" +dependencies = [ + "manyhow-macros", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "manyhow-macros" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495" +dependencies = [ + "proc-macro-utils", + "proc-macro2", + "quote", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-utils" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071" +dependencies = [ + "proc-macro2", + "quote", + "smallvec", +] + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "qr-link" +version = "0.1.0" +dependencies = [ + "base64 0.21.7", + "base64-serde", + "chrono", + "extism-pdk", + "qrcode", + "serde", + "serde_json", +] + +[[package]] +name = "qrcode" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d68782463e408eb1e668cf6152704bd856c78c5b6417adaee3203d8f4c1fc9ec" + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "serde" +version = "1.0.213" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.213" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.132" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "syn" +version = "2.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "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_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[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_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] diff --git a/examples/qr-link/Cargo.toml b/examples/qr-link/Cargo.toml new file mode 100755 index 0000000..589a912 --- /dev/null +++ b/examples/qr-link/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "qr-link" +version = "0.1.0" +edition = "2021" + +[lib] +name = "plugin" +crate-type = ["cdylib"] + +[dependencies] +extism-pdk = "1.1.0" +chrono = { version = "0.4", features = ["serde"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +base64-serde = "0.7" +base64 = "0.21" +qrcode = { version = "0.14.1", default-features = false } diff --git a/examples/qr-link/src/lib.rs b/examples/qr-link/src/lib.rs new file mode 100755 index 0000000..e4a7216 --- /dev/null +++ b/examples/qr-link/src/lib.rs @@ -0,0 +1,76 @@ +mod pdk; + +use extism_pdk::*; +use pdk::*; +use qrcode::{render::unicode, QrCode}; + +const CHANNEL_ID: &str = "1290809227643977799"; // TODO: when available in schema, get dynamically + +// +pub(crate) fn handle(input: IncomingEvent) -> Result<(), Error> { + match input.kind.as_str() { + "content" if input.message.is_some() => handle_new_message(input.message.unwrap()), + "watch:reaction:added" if input.reaction.is_some() => reply_with_qrcode( + input.guild, + CHANNEL_ID, + input.channel, + input.reaction.unwrap(), + ), + _ => Ok(()), + } +} + +// watch this message, eventually detect a 📱 (:mobile_phone:) emoji to trigger the reply which includes a QR code +fn handle_new_message(input: IncomingMessage) -> Result<(), Error> { + let msg = input.id.clone(); + match watch_message(msg) { + Ok(w) => { + if w.error_code > 0 { + log!(LogLevel::Error, "error watching message: id={}", input.id); + return Err(extism_pdk::Error::msg("failed to watch message")); + } + } + Err(e) => { + log!(LogLevel::Error, "`watch` host call failed: {:?}", e); + return Err(e); + } + } + + Ok(()) +} + +fn reply_with_qrcode( + server_id: impl AsRef, + channel_id: impl AsRef, + channel_name: impl AsRef, + reaction: IncomingReaction, +) -> Result<(), Error> { + if reaction.with.name != "📱" { + return Ok(()); + } + + // generate a QR code using a computed URL to jump to this message + // https://discord.com/channels/1011124058408112148/1290809227643977799/1299105987684339824 + let msg_url = format!( + "https://discord.com/channels/{}/{}/{}", + server_id.as_ref(), + channel_id.as_ref(), + reaction.message.id + ); + + // convert the url into a QR code string, using some ascii text ideally to render nicely in Discord + let code = QrCode::new(msg_url)?; + let image = code + .render::() + .dark_color(unicode::Dense1x2::Dark) + .light_color(unicode::Dense1x2::Light) + .build(); + + send_message(OutgoingMessage { + channel: Some(channel_name.as_ref().into()), + message: format!("```\n{}\n```", image), + reply: Some(reaction.message.id), + })?; + + Ok(()) +} diff --git a/examples/qr-link/src/pdk.rs b/examples/qr-link/src/pdk.rs new file mode 100755 index 0000000..32b8cdd --- /dev/null +++ b/examples/qr-link/src/pdk.rs @@ -0,0 +1,259 @@ +// THIS FILE WAS GENERATED BY `xtp-rust-bindgen`. DO NOT EDIT. + +#![allow(unused_macros)] +#![allow(non_snake_case)] +use extism_pdk::*; +use serde::{Deserialize, Serialize}; + +fn return_error(e: Error) -> i32 { + let err = format!("{:?}", e); + let mem = extism_pdk::Memory::from_bytes(&err).unwrap(); + unsafe { + extism_pdk::extism::error_set(mem.offset()); + } + -1 +} + +macro_rules! try_input { + () => {{ + let x = input(); + match x { + Ok(x) => x, + Err(e) => return return_error(e), + } + }}; +} + +macro_rules! try_input_json { + () => {{ + let x = input(); + match x { + Ok(Json(x)) => x, + Err(e) => return return_error(e), + } + }}; +} + +use base64_serde::base64_serde_type; + +base64_serde_type!(Base64Standard, base64::engine::general_purpose::STANDARD); + +#[no_mangle] +pub extern "C" fn handle() -> i32 { + let ret = crate::handle(try_input_json!()).and_then(output); + + match ret { + Ok(()) => 0, + Err(e) => return_error(e), + } +} + +#[derive(Serialize, Deserialize, FromBytes, ToBytes)] +#[encoding(Json)] +pub struct Emoji { + // whether or not the emoji is animated + #[serde(rename = "animated")] + pub animated: Option, + // The id of the reaction (if custom); null if a built-in emoji + #[serde(rename = "id")] + #[serde(default)] + pub id: Option, + // the name used for the reactji; built-in emoji will be the literal character, otherwise the text name appears here + #[serde(rename = "name")] + pub name: String, +} + +#[derive(Serialize, Deserialize, FromBytes, ToBytes)] +#[encoding(Json)] +pub struct HandlerResult { + // An error code. Zero indicates success. Negative numbers indicate failure. + #[serde(rename = "errorCode")] + pub error_code: i64, + // An id for the result + #[serde(rename = "id")] + #[serde(default)] + pub id: Option, +} + +#[derive(Serialize, Deserialize, FromBytes, ToBytes)] +#[encoding(Json)] +pub struct IncomingEvent { + // The channel the message was received in + #[serde(rename = "channel")] + pub channel: String, + // The guild the message was received in + #[serde(rename = "guild")] + pub guild: String, + // The kind of event (one of "content", "watch:reference", "watch:reaction:added", "watch:reaction:removed", "http:response") + #[serde(rename = "kind")] + pub kind: String, + // An incoming message + #[serde(rename = "message")] + #[serde(default)] + pub message: Option, + // A reaction happened + #[serde(rename = "reaction")] + #[serde(default)] + pub reaction: Option, + // We received a response + #[serde(rename = "response")] + #[serde(default)] + pub response: Option, +} + +#[derive(Serialize, Deserialize, FromBytes, ToBytes)] +#[encoding(Json)] +pub struct IncomingMessage { + // The username of the author of the message + #[serde(rename = "author")] + pub author: String, + // The message text + #[serde(rename = "content")] + pub content: String, + // An id identifying the message. + #[serde(rename = "id")] + pub id: String, + // The id of the message to which this message replies + #[serde(rename = "reference")] + #[serde(default)] + pub reference: Option, +} + +#[derive(Serialize, Deserialize, FromBytes, ToBytes)] +#[encoding(Json)] +pub struct IncomingReaction { + // The username that reacted + #[serde(rename = "from")] + pub from: String, + // An incoming message + #[serde(rename = "message")] + pub message: IncomingMessage, + // An emoji used to react + #[serde(rename = "with")] + pub with: Emoji, +} + +#[derive(Serialize, Deserialize, FromBytes, ToBytes)] +#[encoding(Json)] +pub struct IncomingResponse { + // the http body + #[serde(rename = "body")] + pub body: String, + // the http headers + #[serde(rename = "headers")] + pub headers: std::collections::HashMap, + // the identifier the plugin sent + #[serde(rename = "id")] + pub id: String, + // the http status code + #[serde(rename = "status")] + pub status: i64, +} + +#[derive(Serialize, Deserialize, FromBytes, ToBytes)] +#[encoding(Json)] +pub struct OutgoingMessage { + // The channel the message was received in + #[serde(rename = "channel")] + #[serde(default)] + pub channel: Option, + // The message text + #[serde(rename = "message")] + pub message: String, + // A message ID to reply to + #[serde(rename = "reply")] + #[serde(default)] + pub reply: Option, +} + +#[derive(Serialize, Deserialize, FromBytes, ToBytes)] +#[encoding(Json)] +pub struct OutgoingReaction { + // the message id + #[serde(rename = "messageId")] + pub message_id: String, + // The emoji reaction + #[serde(rename = "with")] + pub with: String, +} + +#[derive(Serialize, Deserialize, FromBytes, ToBytes)] +#[encoding(Json)] +pub struct OutgoingRequest { + // the http body + #[serde(rename = "body")] + pub body: String, + // the http headers + #[serde(rename = "headers")] + pub headers: std::collections::HashMap, + // the http method + #[serde(rename = "method")] + pub method: String, + // the url + #[serde(rename = "url")] + pub url: String, +} + +mod raw_imports { + use super::*; + #[host_fn] + extern "ExtismHost" { + + pub(crate) fn react(input: Json) -> Json; + + pub(crate) fn request(input: Json) -> Json; + + pub(crate) fn sendMessage(input: Json) -> Json; + + pub(crate) fn watchMessage(input: String) -> Json; + + } +} + +// react +// It takes input of OutgoingReaction (send a reaction) +// And it returns an output HandlerResult (A result.) +#[allow(unused)] +pub(crate) fn react(input: OutgoingReaction) -> Result { + let res = unsafe { raw_imports::react(Json(input))? }; + + let Json(res) = res; + + Ok(res) +} + +// request +// It takes input of OutgoingRequest (An HTTP request) +// And it returns an output HandlerResult (A result.) +#[allow(unused)] +pub(crate) fn request(input: OutgoingRequest) -> Result { + let res = unsafe { raw_imports::request(Json(input))? }; + + let Json(res) = res; + + Ok(res) +} + +// sendMessage +// It takes input of OutgoingMessage (An outgoing message) +// And it returns an output HandlerResult (A result.) +#[allow(unused)] +pub(crate) fn send_message(input: OutgoingMessage) -> Result { + let res = unsafe { raw_imports::sendMessage(Json(input))? }; + + let Json(res) = res; + + Ok(res) +} + +// watchMessage +// It takes input of String (the id of a message to watch) +// And it returns an output HandlerResult (A result.) +#[allow(unused)] +pub(crate) fn watch_message(input: String) -> Result { + let res = unsafe { raw_imports::watchMessage(input)? }; + + let Json(res) = res; + + Ok(res) +} diff --git a/examples/qr-link/xtp.toml b/examples/qr-link/xtp.toml new file mode 100755 index 0000000..5815119 --- /dev/null +++ b/examples/qr-link/xtp.toml @@ -0,0 +1,17 @@ +app_id = "app_01j8r463d3f6c91hdevkctb7cw" + +# This is where 'xtp plugin push' expects to find the wasm file after the build script has run. +bin = "target/wasm32-wasi/release/plugin.wasm" +extension_point_id = "ext_01j8r4jqawfd6tjxh85t3988kc" +name = "qr-link" + +[scripts] + + # xtp plugin build runs this script to generate the wasm file + build = "cargo build --release --target wasm32-wasi" + + # xtp plugin init runs this script to format the plugin code + format = "cargo fmt" + + # xtp plugin init runs this script before running the format script + prepare = ""