fast commit #26

Merged
akulij merged 1 commits from dev into main 2025-06-18 17:32:42 +00:00
25 changed files with 1750 additions and 1047 deletions

538
Cargo.lock generated
View File

@ -106,6 +106,12 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "az"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973"
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.74" version = "0.3.74"
@ -139,6 +145,25 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "base64-simd"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195"
dependencies = [
"outref",
"vsimd",
]
[[package]]
name = "bincode"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "bindgen" name = "bindgen"
version = "0.71.1" version = "0.71.1"
@ -159,6 +184,21 @@ dependencies = [
"syn 2.0.100", "syn 2.0.100",
] ]
[[package]]
name = "bit-set"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
dependencies = [
"bit-vec",
]
[[package]]
name = "bit-vec"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "1.3.2"
@ -216,6 +256,16 @@ dependencies = [
"uuid", "uuid",
] ]
[[package]]
name = "bstr"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4"
dependencies = [
"memchr",
"serde",
]
[[package]] [[package]]
name = "build-time" name = "build-time"
version = "0.1.3" version = "0.1.3"
@ -253,6 +303,26 @@ version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "capacity_builder"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f2d24a6dcf0cd402a21b65d35340f3a49ff3475dc5fdac91d22d2733e6641c6"
dependencies = [
"capacity_builder_macros",
"itoa",
]
[[package]]
name = "capacity_builder_macros"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b4a6cae9efc04cc6cbb8faf338d2c497c165c83e74509cf4dbedea948bbf6e5"
dependencies = [
"quote",
"syn 2.0.100",
]
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.17" version = "1.2.17"
@ -370,6 +440,12 @@ dependencies = [
"unicode-segmentation", "unicode-segmentation",
] ]
[[package]]
name = "cooked-waker"
version = "5.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f"
[[package]] [[package]]
name = "copy_dir" name = "copy_dir"
version = "0.1.3" version = "0.1.3"
@ -419,6 +495,15 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
[[package]]
name = "crc32fast"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "crossbeam-queue" name = "crossbeam-queue"
version = "0.3.12" version = "0.3.12"
@ -491,6 +576,126 @@ version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476"
[[package]]
name = "debugid"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d"
dependencies = [
"serde",
"uuid",
]
[[package]]
name = "deno_core"
version = "0.350.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e273b731fce500130790e777cb2631dc451db412975304d23816c1e444a10c5b"
dependencies = [
"anyhow",
"az",
"bincode",
"bit-set",
"bit-vec",
"bytes",
"capacity_builder",
"cooked-waker",
"deno_core_icudata",
"deno_error",
"deno_ops",
"deno_path_util",
"deno_unsync",
"futures",
"indexmap 2.8.0",
"libc",
"parking_lot",
"percent-encoding",
"pin-project",
"serde",
"serde_json",
"serde_v8",
"smallvec",
"sourcemap",
"static_assertions",
"thiserror 2.0.12",
"tokio",
"url",
"v8",
"wasm_dep_analyzer",
]
[[package]]
name = "deno_core_icudata"
version = "0.74.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe4dccb6147bb3f3ba0c7a48e993bfeb999d2c2e47a81badee80e2b370c8d695"
[[package]]
name = "deno_error"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "612ec3fc481fea759141b0c57810889b0a4fb6fee8f10748677bfe492fd30486"
dependencies = [
"deno_error_macro",
"libc",
"serde",
"serde_json",
"tokio",
"url",
]
[[package]]
name = "deno_error_macro"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8380a4224d5d2c3f84da4d764c4326cac62e9a1e3d4960442d29136fc07be863"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "deno_ops"
version = "0.226.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28b12489187c71fa123731cc783d48beb17ae5df04da991909cc2ae5a3d0ef9"
dependencies = [
"indexmap 2.8.0",
"proc-macro-rules",
"proc-macro2",
"quote",
"stringcase",
"strum",
"strum_macros",
"syn 2.0.100",
"thiserror 2.0.12",
]
[[package]]
name = "deno_path_util"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "516f813389095889776b81cc9108ff6f336fd9409b4b12fc0138aea23d2708e1"
dependencies = [
"deno_error",
"percent-encoding",
"sys_traits",
"thiserror 2.0.12",
"url",
]
[[package]]
name = "deno_unsync"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6742a724e8becb372a74c650a1aefb8924a5b8107f7d75b3848763ea24b27a87"
dependencies = [
"futures-util",
"parking_lot",
"tokio",
]
[[package]] [[package]]
name = "deranged" name = "deranged"
version = "0.4.1" version = "0.4.1"
@ -676,6 +881,16 @@ dependencies = [
"scopeguard", "scopeguard",
] ]
[[package]]
name = "erased-serde"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7"
dependencies = [
"serde",
"typeid",
]
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.3.10" version = "0.3.10"
@ -761,6 +976,16 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "fslock"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb"
dependencies = [
"libc",
"winapi",
]
[[package]] [[package]]
name = "funty" name = "funty"
version = "2.0.0" version = "2.0.0"
@ -926,11 +1151,13 @@ checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
name = "gongbotrs" name = "gongbotrs"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow",
"async-trait", "async-trait",
"bson", "bson",
"build-time", "build-time",
"chrono", "chrono",
"chrono-tz", "chrono-tz",
"deno_core",
"dotenvy", "dotenvy",
"enum_stringify", "enum_stringify",
"envconfig", "envconfig",
@ -939,14 +1166,26 @@ dependencies = [
"itertools 0.14.0", "itertools 0.14.0",
"lazy_static", "lazy_static",
"log", "log",
"mlua",
"mongodb", "mongodb",
"pretty_env_logger", "pretty_env_logger",
"quickjs-rusty", "quickjs-rusty",
"serde", "serde",
"serde_json", "serde_json",
"serde_v8",
"teloxide", "teloxide",
"thiserror 2.0.12", "thiserror 2.0.12",
"tokio", "tokio",
"v8",
]
[[package]]
name = "gzip-header"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95cc527b92e6029a62960ad99aa8a6660faa4555fe5f731aab13aa6a921795a2"
dependencies = [
"crc32fast",
] ]
[[package]] [[package]]
@ -1345,6 +1584,12 @@ dependencies = [
"icu_properties", "icu_properties",
] ]
[[package]]
name = "if_chain"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed"
[[package]] [[package]]
name = "include_dir" name = "include_dir"
version = "0.7.4" version = "0.7.4"
@ -1508,6 +1753,12 @@ version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "linux-raw-sys"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.9.3" version = "0.9.3"
@ -1545,6 +1796,15 @@ dependencies = [
"linked-hash-map", "linked-hash-map",
] ]
[[package]]
name = "luau0-src"
version = "0.12.3+luau663"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76ae337c644bbf86a8d8e9ce3ee023311833d41741baf5e51acc31b37843aba1"
dependencies = [
"cc",
]
[[package]] [[package]]
name = "macro_magic" name = "macro_magic"
version = "0.5.1" version = "0.5.1"
@ -1633,9 +1893,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.8.5" version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [ dependencies = [
"adler2", "adler2",
] ]
@ -1651,6 +1911,37 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "mlua"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1f5f8fbebc7db5f671671134b9321c4b9aa9adeafccfd9a8c020ae45c6a35d0"
dependencies = [
"bstr",
"either",
"erased-serde",
"libloading",
"mlua-sys",
"num-traits",
"parking_lot",
"rustc-hash",
"rustversion",
"serde",
"serde-value",
]
[[package]]
name = "mlua-sys"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380c1f7e2099cafcf40e51d3a9f20a346977587aa4d012eae1f043149a728a93"
dependencies = [
"cc",
"cfg-if",
"luau0-src",
"pkg-config",
]
[[package]] [[package]]
name = "mongodb" name = "mongodb"
version = "3.2.3" version = "3.2.3"
@ -1747,6 +2038,7 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [ dependencies = [
"num-integer", "num-integer",
"num-traits", "num-traits",
"rand 0.8.5",
] ]
[[package]] [[package]]
@ -1832,6 +2124,21 @@ dependencies = [
"vcpkg", "vcpkg",
] ]
[[package]]
name = "ordered-float"
version = "2.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c"
dependencies = [
"num-traits",
]
[[package]]
name = "outref"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e"
[[package]] [[package]]
name = "parking" name = "parking"
version = "2.2.1" version = "2.2.1"
@ -1870,6 +2177,12 @@ dependencies = [
"regex", "regex",
] ]
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]] [[package]]
name = "pbkdf2" name = "pbkdf2"
version = "0.11.0" version = "0.11.0"
@ -2017,6 +2330,29 @@ dependencies = [
"quote", "quote",
] ]
[[package]]
name = "proc-macro-rules"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07c277e4e643ef00c1233393c673f655e3672cf7eb3ba08a00bdd0ea59139b5f"
dependencies = [
"proc-macro-rules-macros",
"proc-macro2",
"syn 2.0.100",
]
[[package]]
name = "proc-macro-rules-macros"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "207fffb0fe655d1d47f6af98cc2793405e85929bdbc420d685554ff07be27ac7"
dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.94" version = "1.0.94"
@ -2275,6 +2611,19 @@ dependencies = [
"semver", "semver",
] ]
[[package]]
name = "rustix"
version = "0.38.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
dependencies = [
"bitflags 2.9.0",
"errno",
"libc",
"linux-raw-sys 0.4.15",
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "1.0.3" version = "1.0.3"
@ -2284,7 +2633,7 @@ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.0",
"errno", "errno",
"libc", "libc",
"linux-raw-sys", "linux-raw-sys 0.9.3",
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
@ -2418,6 +2767,16 @@ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]]
name = "serde-value"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
dependencies = [
"ordered-float",
"serde",
]
[[package]] [[package]]
name = "serde_bytes" name = "serde_bytes"
version = "0.11.17" version = "0.11.17"
@ -2463,6 +2822,20 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serde_v8"
version = "0.259.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7e4c5f439cffc03021c8bfd380cd1ef6acb4788a72b7e54bf4a83c73f91f8a0"
dependencies = [
"deno_error",
"num-bigint",
"serde",
"smallvec",
"thiserror 2.0.12",
"v8",
]
[[package]] [[package]]
name = "serde_with" name = "serde_with"
version = "3.12.0" version = "3.12.0"
@ -2564,6 +2937,24 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "sourcemap"
version = "9.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e22afbcb92ce02d23815b9795523c005cb9d3c214f8b7a66318541c240ea7935"
dependencies = [
"base64-simd",
"bitvec",
"data-encoding",
"debugid",
"if_chain",
"rustc-hash",
"serde",
"serde_json",
"unicode-id-start",
"url",
]
[[package]] [[package]]
name = "spin" name = "spin"
version = "0.9.8" version = "0.9.8"
@ -2723,6 +3114,18 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "stringcase"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72abeda133c49d7bddece6c154728f83eec8172380c80ab7096da9487e20d27c"
[[package]] [[package]]
name = "stringprep" name = "stringprep"
version = "0.1.5" version = "0.1.5"
@ -2740,6 +3143,28 @@ version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "strum"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.100",
]
[[package]] [[package]]
name = "subtle" name = "subtle"
version = "2.6.1" version = "2.6.1"
@ -2788,6 +3213,26 @@ dependencies = [
"syn 2.0.100", "syn 2.0.100",
] ]
[[package]]
name = "sys_traits"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc4707edf3196e8037ee45018d1bb1bfb233b0e4fc440fa3d3f25bc69bfdaf26"
dependencies = [
"sys_traits_macros",
]
[[package]]
name = "sys_traits_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "181f22127402abcf8ee5c83ccd5b408933fec36a6095cf82cda545634692657e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]] [[package]]
name = "take_mut" name = "take_mut"
version = "0.2.2" version = "0.2.2"
@ -2885,7 +3330,7 @@ dependencies = [
"fastrand", "fastrand",
"getrandom 0.3.2", "getrandom 0.3.2",
"once_cell", "once_cell",
"rustix", "rustix 1.0.3",
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
@ -3013,6 +3458,7 @@ dependencies = [
"bytes", "bytes",
"libc", "libc",
"mio", "mio",
"parking_lot",
"pin-project-lite", "pin-project-lite",
"signal-hook-registry", "signal-hook-registry",
"socket2", "socket2",
@ -3152,6 +3598,12 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "typeid"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.18.0" version = "1.18.0"
@ -3170,6 +3622,12 @@ version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
[[package]]
name = "unicode-id-start"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f322b60f6b9736017344fa0635d64be2f458fbc04eef65f6be22976dd1ffd5b"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.18" version = "1.0.18"
@ -3245,6 +3703,22 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "v8"
version = "137.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2b387c1c5731284e756c03280032068e68e5b52f6c4714492403c30f650ad52"
dependencies = [
"bindgen",
"bitflags 2.9.0",
"fslock",
"gzip-header",
"home",
"miniz_oxide",
"paste",
"which",
]
[[package]] [[package]]
name = "vcpkg" name = "vcpkg"
version = "0.2.15" version = "0.2.15"
@ -3257,6 +3731,12 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "vsimd"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64"
[[package]] [[package]]
name = "walkdir" name = "walkdir"
version = "2.5.0" version = "2.5.0"
@ -3381,6 +3861,16 @@ dependencies = [
"web-sys", "web-sys",
] ]
[[package]]
name = "wasm_dep_analyzer"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51cf5f08b357e64cd7642ab4bbeb11aecab9e15520692129624fb9908b8df2c"
dependencies = [
"deno_error",
"thiserror 2.0.12",
]
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.77" version = "0.3.77"
@ -3397,6 +3887,18 @@ version = "0.25.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
[[package]]
name = "which"
version = "6.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f"
dependencies = [
"either",
"home",
"rustix 0.38.44",
"winsafe",
]
[[package]] [[package]]
name = "whoami" name = "whoami"
version = "1.6.0" version = "1.6.0"
@ -3413,6 +3915,22 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]] [[package]]
name = "winapi-util" name = "winapi-util"
version = "0.1.9" version = "0.1.9"
@ -3422,6 +3940,12 @@ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]] [[package]]
name = "windows-core" name = "windows-core"
version = "0.52.0" version = "0.52.0"
@ -3688,6 +4212,12 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "winsafe"
version = "0.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
[[package]] [[package]]
name = "wit-bindgen-rt" name = "wit-bindgen-rt"
version = "0.39.0" version = "0.39.0"

View File

@ -6,11 +6,13 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
anyhow = "1.0.98"
async-trait = "0.1.88" async-trait = "0.1.88"
bson = { version = "2.14.0", features = ["chrono-0_4"] } bson = { version = "2.14.0", features = ["chrono-0_4"] }
build-time = "0.1.3" build-time = "0.1.3"
chrono = { version = "0.4.40", features = ["serde"] } chrono = { version = "0.4.40", features = ["serde"] }
chrono-tz = "0.10.3" chrono-tz = "0.10.3"
deno_core = "0.350.0"
dotenvy = "0.15.7" dotenvy = "0.15.7"
enum_stringify = "0.6.3" enum_stringify = "0.6.3"
envconfig = "0.11.0" envconfig = "0.11.0"
@ -19,14 +21,17 @@ git-const = "1.1.0"
itertools = "0.14.0" itertools = "0.14.0"
lazy_static = "1.5.0" lazy_static = "1.5.0"
log = "0.4.27" log = "0.4.27"
mlua = { version = "0.10.5", features = ["luau", "serialize"] }
mongodb = "3.2.3" mongodb = "3.2.3"
pretty_env_logger = "0.5.0" pretty_env_logger = "0.5.0"
quickjs-rusty = { git = "https://github.com/akulij/quickjs-rusty.git", rev = "549f830" } quickjs-rusty = { git = "https://github.com/akulij/quickjs-rusty.git", rev = "549f830" }
serde = { version = "1.0.219", features = ["derive", "serde_derive"] } serde = { version = "1.0.219", features = ["derive", "serde_derive"] }
serde_json = "1.0.140" serde_json = "1.0.140"
serde_v8 = "0.259.0"
teloxide = { version = "0.14.0", features = ["macros", "postgres-storage-nativetls"] } teloxide = { version = "0.14.0", features = ["macros", "postgres-storage-nativetls"] }
thiserror = "2.0.12" thiserror = "2.0.12"
tokio = { version = "1.44.1", features = ["rt-multi-thread", "macros"] } tokio = { version = "1.44.1", features = ["rt-multi-thread", "macros"] }
v8 = "137.2.0"
[lints.clippy] [lints.clippy]
print_stdout = "warn" print_stdout = "warn"

View File

@ -93,14 +93,22 @@ print(JSON.stringify(dialog.buttons))
const config = { const config = {
version: 1.1, version: 1.1,
timezone: 3, timezone: 5,
} }
const notifications = [ const notifications = [
{
// time: "17:38",
time: {once: "17:49"},
message: {literal: "show_projects"},
},
// { // {
// time: "18:14", // time: {
// message: {literal: "show_projects"}, // hour: 0,
// delta_minutes: 2,
// }, // },
// message: {literal: "show_projects"},
// }
] ]
// {config, dialog} // {config, dialog}

View File

@ -15,8 +15,13 @@ use teloxide::{
}; };
use crate::{ use crate::{
botscript::{self, message_info::MessageInfoBuilder, BotMessage, ScriptError}, botscript::{self, message_info::MessageInfoBuilder, ScriptError},
commands::BotCommand, commands::BotCommand,
config::{
dialog::{button::ButtonLayout, message::BotMessage},
traits::ProviderSerialize,
Provider,
},
db::{callback_info::CallbackInfo, CallDB, DB}, db::{callback_info::CallbackInfo, CallDB, DB},
message_answerer::MessageAnswerer, message_answerer::MessageAnswerer,
notify_admin, update_user_tg, notify_admin, update_user_tg,
@ -29,7 +34,7 @@ pub type BotHandler =
type CallbackStore = CallbackInfo<Value>; type CallbackStore = CallbackInfo<Value>;
pub fn script_handler(r: Arc<Mutex<BotRuntime>>) -> BotHandler { pub fn script_handler<P: Provider + Send + Sync>(r: Arc<Mutex<BotRuntime<P>>>) -> BotHandler {
let cr = r.clone(); let cr = r.clone();
dptree::entry() dptree::entry()
.branch( .branch(
@ -91,8 +96,13 @@ pub fn script_handler(r: Arc<Mutex<BotRuntime>>) -> BotHandler {
) )
} }
async fn handle_botmessage(bot: Bot, mut db: DB, bm: BotMessage, msg: Message) -> BotResult<()> { async fn handle_botmessage<P: Provider>(
info!("Eval BM: {:?}", bm); bot: Bot,
mut db: DB,
bm: BotMessage<P>,
msg: Message,
) -> BotResult<()> {
// info!("Eval BM: {:?}", bm);
let tguser = match msg.from.clone() { let tguser = match msg.from.clone() {
Some(user) => user, Some(user) => user,
None => return Ok(()), // do nothing, cause its not usecase of function None => return Ok(()), // do nothing, cause its not usecase of function
@ -116,31 +126,34 @@ async fn handle_botmessage(bot: Bot, mut db: DB, bm: BotMessage, msg: Message) -
let is_propagate: bool = match bm.get_handler() { let is_propagate: bool = match bm.get_handler() {
Some(handler) => 'prop: { Some(handler) => 'prop: {
let ctx = match handler.context() { // let ctx = match handler.context() {
Some(ctx) => ctx, // Some(ctx) => ctx,
// falling back to propagation // // falling back to propagation
None => break 'prop true, // None => break 'prop true,
}; // };
let jsuser = to_js(ctx, &tguser).map_err(ScriptError::from)?; // let jsuser = to_js(ctx, &tguser).map_err(ScriptError::from)?;
let puser = <P::Value as ProviderSerialize>::se_from(&tguser).unwrap();
let mi = MessageInfoBuilder::new() let mi = MessageInfoBuilder::new()
.set_variant(variant.clone()) .set_variant(variant.clone())
.build(); .build();
let mi = to_js(ctx, &mi).map_err(ScriptError::from)?; // let mi = to_js(ctx, &mi).map_err(ScriptError::from)?;
info!( let pmi = <P::Value as ProviderSerialize>::se_from(&mi).unwrap();
"Calling handler {:?} with msg literal: {:?}", // info!(
handler, // "Calling handler {:?} with msg literal: {:?}",
bm.literal() // handler,
); // bm.literal()
match handler.call_args(vec![jsuser, mi]) { // );
match handler.call_args(vec![puser, pmi]) {
Ok(v) => { Ok(v) => {
if v.is_bool() { todo!()
v.to_bool().unwrap_or(true) // if v.is_bool() {
} else if v.is_int() { // v.to_bool().unwrap_or(true)
v.to_int().unwrap_or(1) != 0 // } else if v.is_int() {
} else { // v.to_int().unwrap_or(1) != 0
// falling back to propagation // } else {
true // // falling back to propagation
} // true
// }
} }
Err(err) => { Err(err) => {
error!("Failed to get return of handler, err: {err}"); error!("Failed to get return of handler, err: {err}");
@ -161,7 +174,7 @@ async fn handle_botmessage(bot: Bot, mut db: DB, bm: BotMessage, msg: Message) -
join_all(buttons.iter().map(async |r| { join_all(buttons.iter().map(async |r| {
join_all(r.iter().map(async |b| { join_all(r.iter().map(async |b| {
match b { match b {
botscript::ButtonLayout::Callback { ButtonLayout::Callback {
name, name,
literal: _, literal: _,
callback, callback,
@ -198,9 +211,14 @@ async fn handle_botmessage(bot: Bot, mut db: DB, bm: BotMessage, msg: Message) -
Ok(()) Ok(())
} }
async fn handle_callback(bot: Bot, mut db: DB, bm: BotMessage, q: CallbackQuery) -> BotResult<()> { async fn handle_callback<P: Provider>(
bot: Bot,
mut db: DB,
bm: BotMessage<P>,
q: CallbackQuery,
) -> BotResult<()> {
bot.answer_callback_query(&q.id).await?; bot.answer_callback_query(&q.id).await?;
info!("Eval BM: {:?}", bm); // info!("Eval BM: {:?}", bm);
let tguser = q.from.clone(); let tguser = q.from.clone();
let user = db let user = db
.get_or_init_user(tguser.id.0 as i64, &tguser.first_name) .get_or_init_user(tguser.id.0 as i64, &tguser.first_name)
@ -210,24 +228,20 @@ async fn handle_callback(bot: Bot, mut db: DB, bm: BotMessage, q: CallbackQuery)
let is_propagate: bool = match bm.get_handler() { let is_propagate: bool = match bm.get_handler() {
Some(handler) => 'prop: { Some(handler) => 'prop: {
let ctx = match handler.context() { let puser = <P::Value as ProviderSerialize>::se_from(&tguser).unwrap();
Some(ctx) => ctx,
// falling back to propagation
None => break 'prop true,
};
let jsuser = to_js(ctx, &tguser).map_err(ScriptError::from)?;
let mi = MessageInfoBuilder::new().build(); let mi = MessageInfoBuilder::new().build();
let mi = to_js(ctx, &mi).map_err(ScriptError::from)?; let pmi = <P::Value as ProviderSerialize>::se_from(&mi).unwrap();
match handler.call_args(vec![jsuser, mi]) { match handler.call_args(vec![puser, pmi]) {
Ok(v) => { Ok(v) => {
if v.is_bool() { todo!()
v.to_bool().unwrap_or(true) // if v.is_bool() {
} else if v.is_int() { // v.to_bool().unwrap_or(true)
v.to_int().unwrap_or(1) != 0 // } else if v.is_int() {
} else { // v.to_int().unwrap_or(1) != 0
// falling back to propagation // } else {
true // // falling back to propagation
} // true
// }
} }
Err(err) => { Err(err) => {
error!("Failed to get return of handler, err: {err}"); error!("Failed to get return of handler, err: {err}");
@ -248,7 +262,7 @@ async fn handle_callback(bot: Bot, mut db: DB, bm: BotMessage, q: CallbackQuery)
join_all(buttons.iter().map(async |r| { join_all(buttons.iter().map(async |r| {
join_all(r.iter().map(async |b| { join_all(r.iter().map(async |b| {
match b { match b {
botscript::ButtonLayout::Callback { ButtonLayout::Callback {
name, name,
literal: _, literal: _,
callback, callback,

View File

@ -40,32 +40,28 @@ pub struct BotInfo {
pub static DEFAULT_SCRIPT: &str = pub static DEFAULT_SCRIPT: &str =
include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/default_script.js")); include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/default_script.js"));
pub struct BotManager<BIG, HM, BIS, HI, FBIS, FHI> pub struct BotManager<BIG, BHG, BII, BHI>
where where
BIG: FnMut() -> FBIS, BIG: AsyncFnMut() -> BII, // BotInstance Getter
FBIS: Future<Output = BIS>, BII: Iterator<Item = BotInstance>, // BotInstance Iterator
BIS: Iterator<Item = BotInstance>, BHG: AsyncFnMut(BotInstance) -> BHI, // BotHandler Getter
HM: FnMut(BotInstance) -> FHI, BHI: Iterator<Item = BotHandler>, // BotHandler Iterator
FHI: Future<Output = HI>,
HI: Iterator<Item = BotHandler>,
{ {
bot_pool: HashMap<String, BotRunner>, bot_pool: HashMap<String, BotRunner>,
bi_getter: BIG, bi_getter: BIG,
h_mapper: HM, h_mapper: BHG,
} }
impl<BIG, HM, BIS, HI, FBIS, FHI> BotManager<BIG, HM, BIS, HI, FBIS, FHI> impl<BIG, BHG, BII, BHI> BotManager<BIG, BHG, BII, BHI>
where where
BIG: FnMut() -> FBIS, BIG: AsyncFnMut() -> BII, // BotInstance Getter
FBIS: Future<Output = BIS>, BII: Iterator<Item = BotInstance>, // BotInstance Iterator
BIS: Iterator<Item = BotInstance>, BHG: AsyncFnMut(BotInstance) -> BHI, // BotHandler Getter
HM: FnMut(BotInstance) -> FHI, BHI: Iterator<Item = BotHandler>, // BotHandler Iterator
FHI: Future<Output = HI>,
HI: Iterator<Item = BotHandler>,
{ {
/// bi_getter - fnmut that returns iterator over BotInstance /// bi_getter - async fnmut that returns iterator over BotInstance
/// h_map - fnmut that returns iterator over handlers by BotInstance /// h_map - async fnmut that returns iterator over handlers by BotInstance
pub fn with(bi_getter: BIG, h_mapper: HM) -> Self { pub fn with(bi_getter: BIG, h_mapper: BHG) -> Self {
Self { Self {
bot_pool: Default::default(), bot_pool: Default::default(),
bi_getter, bi_getter,

File diff suppressed because it is too large Load Diff

119
src/config/dialog/button.rs Normal file
View File

@ -0,0 +1,119 @@
use serde::{Deserialize, Serialize};
use crate::{
config::{
function::BotFunction,
result::{ConfigError, ConfigResult},
traits::{ProviderDeserialize, ResolveValue},
Provider,
},
db::{CallDB, DB},
notify_admin,
};
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum ButtonDefinition<P: Provider> {
Button(ButtonRaw),
ButtonLiteral(String),
Function(BotFunction<P>),
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ButtonRaw {
name: ButtonName,
callback_name: String,
}
impl ButtonRaw {
pub fn from_literal(literal: String) -> Self {
ButtonRaw {
name: ButtonName::Literal {
literal: literal.clone(),
},
callback_name: literal,
}
}
pub fn name(&self) -> &ButtonName {
&self.name
}
pub fn callback_name(&self) -> &str {
&self.callback_name
}
pub fn literal(&self) -> Option<String> {
match self.name() {
ButtonName::Value { .. } => None,
ButtonName::Literal { literal } => Some(literal.to_string()),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum ButtonName {
Value { name: String },
Literal { literal: String },
}
impl ButtonName {
pub async fn resolve_name(self, db: &mut DB) -> ConfigResult<String> {
match self {
ButtonName::Value { name } => Ok(name),
ButtonName::Literal { literal } => {
let value = db.get_literal_value(&literal).await?;
Ok(match value {
Some(value) => Ok(value),
None => {
notify_admin(&format!("Literal `{literal}` is not set!!!")).await;
Err(ConfigError::Other(format!(
"not found literal `{literal}` in DB"
)))
}
}?)
}
}
}
}
pub enum ButtonLayout {
Callback {
name: String,
literal: Option<String>,
callback: String,
},
}
impl ButtonLayout {
pub async fn resolve_raw(braw: ButtonRaw, db: &mut DB) -> ConfigResult<Self> {
let name = braw.name().clone().resolve_name(db).await?;
let literal = braw.literal();
let callback = braw.callback_name().to_string();
Ok(Self::Callback {
name,
literal,
callback,
})
}
}
impl<P: Provider> ResolveValue for ButtonDefinition<P> {
type Value = ButtonRaw;
type Runtime = P;
fn resolve(self) -> ConfigResult<Self::Value> {
match self {
ButtonDefinition::Button(button) => Ok(button),
ButtonDefinition::ButtonLiteral(l) => Ok(ButtonRaw::from_literal(l)),
ButtonDefinition::Function(f) => <Self as ResolveValue>::resolve(match f.call()? {
Some(t) => Ok(t.de_into().map_err(ConfigError::as_provider_err)?),
None => Err(ConfigError::Other(
"Function didn't return value".to_string(),
)),
}?),
}
}
}

View File

@ -0,0 +1,58 @@
use serde::{Deserialize, Serialize};
use crate::config::{
function::BotFunction,
result::{ConfigError, ConfigResult},
traits::{ProviderDeserialize, ResolveValue},
Provider,
};
use super::button::ButtonDefinition;
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum KeyboardDefinition<P: Provider> {
Rows(Vec<RowDefinition<P>>),
Function(BotFunction<P>),
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum RowDefinition<P: Provider> {
Buttons(Vec<ButtonDefinition<P>>),
Function(BotFunction<P>),
}
impl<P: Provider> ResolveValue for KeyboardDefinition<P> {
type Value = Vec<<RowDefinition<P> as ResolveValue>::Value>;
type Runtime = P;
fn resolve(self) -> ConfigResult<Self::Value> {
match self {
KeyboardDefinition::Rows(rows) => rows.into_iter().map(|r| r.resolve()).collect(),
KeyboardDefinition::Function(f) => <Self as ResolveValue>::resolve(match f.call()? {
Some(t) => Ok(t.de_into().map_err(ConfigError::as_provider_err)?),
None => Err(ConfigError::Other(
"Function didn't return value".to_string(),
)),
}?),
}
}
}
impl<P: Provider> ResolveValue for RowDefinition<P> {
type Value = Vec<<ButtonDefinition<P> as ResolveValue>::Value>;
type Runtime = P;
fn resolve(self) -> ConfigResult<Self::Value> {
match self {
RowDefinition::Buttons(buttons) => buttons.into_iter().map(|b| b.resolve()).collect(),
RowDefinition::Function(f) => <Self as ResolveValue>::resolve(match f.call()? {
Some(t) => Ok(t.de_into().map_err(ConfigError::as_provider_err)?),
None => Err(ConfigError::Other(
"Function didn't return value".to_string(),
)),
}?),
}
}
}

View File

@ -0,0 +1,93 @@
use futures::future::join_all;
use serde::{Deserialize, Serialize};
use crate::{
config::{function::BotFunction, result::ConfigResult, traits::ResolveValue, Provider},
db::DB,
};
use super::{button::ButtonLayout, keyboard::KeyboardDefinition};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct BotMessage<P: Provider> {
// buttons: Vec<Button>
literal: Option<String>,
#[serde(default)]
replace: bool,
buttons: Option<KeyboardDefinition<P>>,
state: Option<String>,
/// flag options to command is meta, so it will be appended to user.metas in db
meta: Option<bool>,
handler: Option<BotFunction<P>>,
}
impl<P: Provider> BotMessage<P> {
pub fn fill_literal(self, l: String) -> Self {
BotMessage {
literal: self.clone().literal.or(Some(l)),
..self
}
}
/// chain of modifications on BotMessage
pub fn update_defaults(self) -> Self {
let bm = self;
// if message is `start`, defaulting meta to true, if not set
match bm.meta {
Some(_) => bm,
None => match &bm.literal {
Some(l) if l == "start" => Self {
meta: Some(true),
..bm
},
_ => bm,
},
}
}
pub fn is_replace(&self) -> bool {
self.replace
}
pub fn get_handler(&self) -> Option<&BotFunction<P>> {
self.handler.as_ref()
}
pub fn meta(&self) -> bool {
self.meta.unwrap_or(false)
}
}
impl<P: Provider> BotMessage<P> {
pub async fn resolve_buttons(
&self,
db: &mut DB,
) -> ConfigResult<Option<Vec<Vec<ButtonLayout>>>> {
let raw_buttons = self.buttons.clone().map(|b| b.resolve()).transpose()?;
match raw_buttons {
Some(braws) => {
let kbd: Vec<Vec<_>> = join_all(braws.into_iter().map(|rows| async {
join_all(rows.into_iter().map(|b| async {
let mut db = db.clone();
ButtonLayout::resolve_raw(b, &mut db).await
}))
.await
.into_iter()
.collect()
}))
.await
.into_iter()
.collect::<Result<_, _>>()?;
Ok(Some(kbd))
}
None => Ok(None),
}
}
pub fn literal(&self) -> Option<&String> {
self.literal.as_ref()
}
}

19
src/config/dialog/mod.rs Normal file
View File

@ -0,0 +1,19 @@
pub mod button;
pub mod keyboard;
pub mod message;
use std::collections::HashMap;
use message::BotMessage;
use serde::{Deserialize, Serialize};
use super::Provider;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct BotDialog<P: Provider> {
pub commands: HashMap<String, BotMessage<P>>,
pub buttons: HashMap<String, BotMessage<P>>,
stateful_msg_handlers: HashMap<String, BotMessage<P>>,
#[serde(default)]
pub(crate) variants: HashMap<String, HashMap<String, BotMessage<P>>>,
}

21
src/config/function.rs Normal file
View File

@ -0,0 +1,21 @@
use serde::{Deserialize, Serialize};
use super::{
result::{ConfigError, ConfigResult},
traits::ProviderCall,
Provider,
};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct BotFunction<P: Provider>(P::Function);
impl<P: Provider> BotFunction<P> {
pub fn call(&self) -> ConfigResult<Option<P::Value>> {
self.call_args(&[])
}
pub fn call_args(&self, args: &[&P::Value]) -> ConfigResult<Option<P::Value>> {
let val = ProviderCall::call(&self.0, args).map_err(ConfigError::as_provider_err)?;
Ok(val)
}
}

128
src/config/mod.rs Normal file
View File

@ -0,0 +1,128 @@
pub mod traits;
pub mod dialog;
pub mod function;
pub mod notification;
pub mod result;
pub mod time;
use std::time::Duration;
use chrono::DateTime;
use chrono::TimeDelta;
use chrono::Utc;
use dialog::message::BotMessage;
use dialog::BotDialog;
use itertools::Itertools;
use notification::batch::NotificationBatch;
use notification::BotNotification;
use serde::Deserialize;
use serde::Serialize;
pub use traits::Provider;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RunnerConfig<P: Provider> {
config: BotConfig,
pub dialog: BotDialog<P>,
#[serde(default)]
notifications: Vec<BotNotification<P>>,
#[serde(skip)]
created_at: ConfigCreatedAt,
}
impl<P: Provider> RunnerConfig<P> {
/// command without starting `/`
pub fn get_command_message(&self, command: &str) -> Option<BotMessage<P>> {
let bm = self.dialog.commands.get(command).cloned();
bm.map(|bm| bm.fill_literal(command.to_string()).update_defaults())
}
pub fn get_command_message_varianted(
&self,
command: &str,
variant: &str,
) -> Option<BotMessage<P>> {
if !self.dialog.commands.contains_key(command) {
return None;
}
// fallback to regular if not found
let bm = match self.dialog.variants.get(command).cloned() {
Some(bm) => bm,
None => return self.get_command_message(command),
};
// get variant of message
let bm = match bm.get(variant).cloned() {
Some(bm) => bm,
None => return self.get_command_message(command),
};
Some(bm.fill_literal(command.to_string()).update_defaults())
}
pub fn get_callback_message(&self, callback: &str) -> Option<BotMessage<P>> {
let bm = self.dialog.buttons.get(callback).cloned();
bm.map(|bm| bm.fill_literal(callback.to_string()))
}
pub fn created_at(&self) -> DateTime<Utc> {
self.timezoned_time(self.created_at.at)
}
pub fn timezoned_time(&self, dt: DateTime<Utc>) -> DateTime<Utc> {
dt + TimeDelta::try_hours(self.config.timezone.into())
.unwrap_or_else(|| TimeDelta::try_hours(0).expect("Timezone UTC+0 does not exists"))
}
/// if None is returned, then garanteed that later calls will also return None,
/// so, if you'll get None, no notifications will be provided later
pub fn get_nearest_notifications(&self) -> Option<NotificationBatch<P>> {
let start_time = self.created_at();
let now = self.timezoned_time(chrono::offset::Utc::now());
let ordered = self
.notifications
.iter()
.filter(|f| f.left_time(start_time, now) > Duration::from_secs(1))
.sorted_by_key(|f| f.left_time(start_time, now))
.collect::<Vec<_>>();
let left = match ordered.first() {
Some(notification) => notification.left_time(start_time, now),
// No notifications provided
None => return None,
};
// get all that should be sent at the same time
let notifications = ordered
.into_iter()
.filter(|n| n.left_time(start_time, now) == left)
.cloned()
.collect::<Vec<_>>();
Some(NotificationBatch::new(left, notifications))
}
}
#[derive(Debug, Clone)]
struct ConfigCreatedAt {
at: DateTime<Utc>,
}
impl Default for ConfigCreatedAt {
fn default() -> Self {
Self {
at: chrono::offset::Utc::now(),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct BotConfig {
version: f64,
/// relative to UTC, for e.g.,
/// timezone = 3 will be UTC+3,
/// timezone =-2 will be UTC-2,
#[serde(default)]
timezone: i8,
}

View File

@ -0,0 +1,28 @@
use std::time::Duration;
use crate::config::Provider;
use super::BotNotification;
#[derive(Debug, Clone)]
pub struct NotificationBatch<P: Provider> {
wait_for: Duration,
notifications: Vec<BotNotification<P>>,
}
impl<P: Provider> NotificationBatch<P> {
pub fn new(wait_for: Duration, notifications: Vec<BotNotification<P>>) -> Self {
Self {
wait_for,
notifications,
}
}
pub fn wait_for(&self) -> Duration {
self.wait_for
}
pub fn notifications(&self) -> &[BotNotification<P>] {
&self.notifications
}
}

View File

@ -0,0 +1,107 @@
use std::time::Duration;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use crate::{
config::{
result::ConfigError,
traits::{ProviderDeserialize, ProviderSerialize},
},
db::{CallDB, User, DB},
};
use super::{function::BotFunction, result::ConfigResult, time::NotificationTime, Provider};
pub mod batch;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct BotNotification<P: Provider> {
time: NotificationTime,
#[serde(default)]
filter: NotificationFilter<P>,
message: NotificationMessage<P>,
}
impl<P: Provider> BotNotification<P> {
pub fn left_time(&self, start_time: DateTime<Utc>, now: DateTime<Utc>) -> Duration {
let next = self.time.when_next(start_time, now);
// immidate notification if time to do it passed
let duration = (next - now).to_std().unwrap_or(Duration::from_secs(0));
// Rounding partitions of seconds
Duration::from_secs(duration.as_secs())
}
pub async fn get_users(&self, db: &DB) -> ConfigResult<Vec<User>> {
self.filter.get_users(db).await
}
pub async fn resolve_message(&self, db: &DB, user: &User) -> ConfigResult<Option<String>> {
self.message.resolve(db, user).await
}
}
#[derive(Serialize, Deserialize, Default, Debug, Clone)]
#[serde(untagged)]
pub enum NotificationFilter<P: Provider> {
#[default]
#[serde(rename = "all")]
All,
/// Send to randomly selected N people
Random { random: u32 },
/// Function that returns list of user id's who should get notification
BotFunction(BotFunction<P>),
}
impl<P: Provider> NotificationFilter<P> {
pub async fn get_users(&self, db: &DB) -> ConfigResult<Vec<User>> {
match self {
NotificationFilter::All => Ok(db.get_users().await?),
NotificationFilter::Random { random } => Ok(db.get_random_users(*random).await?),
NotificationFilter::BotFunction(f) => {
let uids = match f.call()? {
Some(t) => Ok(t),
None => Err(ConfigError::Other(
"Function didn't return value".to_string(),
)),
}?;
let uids: Vec<i64> = uids.de_into().map_err(ConfigError::as_provider_err)?;
let users = db.get_users_by_ids(uids).await?;
Ok(users)
}
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum NotificationMessage<P: Provider> {
Literal {
literal: String,
},
Text {
text: String,
},
/// Function can accept user which will be notified and then return generated message
BotFunction(BotFunction<P>),
}
impl<P: Provider> NotificationMessage<P> {
pub async fn resolve(&self, db: &DB, user: &User) -> ConfigResult<Option<String>> {
match self {
NotificationMessage::Literal { literal } => Ok(db.get_literal_value(literal).await?),
NotificationMessage::Text { text } => Ok(Some(text.to_string())),
NotificationMessage::BotFunction(f) => {
let puser = <P::Value as ProviderSerialize>::se_from(user)
.map_err(ConfigError::as_provider_err)?;
let text = match f.call_args(&[&puser])? {
Some(t) => t.de_into().map_err(ConfigError::as_provider_err)?,
None => None,
};
Ok(text)
}
}
}
}

29
src/config/result.rs Normal file
View File

@ -0,0 +1,29 @@
use std::error::Error;
use crate::db::DbError;
#[derive(thiserror::Error, Debug)]
pub enum ConfigError {
#[error("error from DB: {0:?}")]
DBError(#[from] DbError),
#[error("error from runtime provider: {0:?}")]
ProviderError(String),
// #[error(transparent)]
// Other(#[from] anyhow::Error),
#[error("error other: {0:?}")]
Other(String),
}
pub type ConfigResult<T> = Result<T, ConfigError>;
//
// impl<P: Provider> From<P::Error> for ConfigError<P> {
// fn from(value: P::Error) -> Self {
// ConfigError::ProviderError(value)
// }
// }
impl ConfigError {
pub fn as_provider_err(err: impl Error) -> Self {
Self::ProviderError(format!("ProviderError: {err}"))
}
}

87
src/config/time.rs Normal file
View File

@ -0,0 +1,87 @@
use std::time::Duration;
use chrono::{DateTime, Days, NaiveTime, ParseError, TimeDelta, Timelike, Utc};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum NotificationTime {
Delta {
#[serde(default)]
delta_hours: u32,
#[serde(default)]
delta_minutes: u32,
},
Specific(SpecificTime),
}
impl NotificationTime {
pub fn when_next(&self, start_time: DateTime<Utc>, now: DateTime<Utc>) -> DateTime<Utc> {
match self {
NotificationTime::Delta {
delta_hours,
delta_minutes,
} => {
let delta = TimeDelta::minutes((delta_minutes + delta_hours * 60).into());
let secs_period = delta.num_seconds();
if secs_period == 0 {
return now;
};
let diff = now - start_time;
let passed = diff.num_seconds().abs() % secs_period;
now - Duration::from_secs(passed as u64) + delta
}
NotificationTime::Specific(time) => {
let estimation = now;
let estimation = estimation.with_hour(time.hour.into()).unwrap_or(estimation);
let estimation = estimation
.with_minute(time.minutes.into())
.unwrap_or(estimation);
if estimation < now {
estimation + Days::new(1)
} else {
estimation
}
}
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(try_from = "SpecificTimeFormat")]
pub struct SpecificTime {
hour: u8,
minutes: u8,
}
impl SpecificTime {
pub fn new(hour: u8, minutes: u8) -> Self {
Self { hour, minutes }
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum SpecificTimeFormat {
String(String),
Verbose { hour: u8, minutes: u8 },
}
impl TryFrom<SpecificTimeFormat> for SpecificTime {
type Error = ParseError;
fn try_from(stf: SpecificTimeFormat) -> Result<Self, Self::Error> {
match stf {
SpecificTimeFormat::Verbose { hour, minutes } => Ok(Self::new(hour, minutes)),
SpecificTimeFormat::String(timestring) => {
let time: NaiveTime = timestring.parse()?;
Ok(Self::new(time.hour() as u8, time.minute() as u8))
}
}
}
}

5
src/config/traits/mod.rs Normal file
View File

@ -0,0 +1,5 @@
mod provider;
mod resolve_value;
pub use provider::*;
pub use resolve_value::*;

View File

@ -0,0 +1,50 @@
use std::fmt::Debug;
use serde::{Deserialize, Serialize};
use std::error::Error;
use crate::config::RunnerConfig;
pub trait Provider: Clone {
type Function: ProviderCall<Provider = Self>
+ Serialize
+ for<'a> Deserialize<'a>
+ Debug
+ Send
+ Sync
+ Clone;
type Value: ProviderDeserialize<Provider = Self>
+ ProviderSerialize<Provider = Self>
+ Serialize
+ for<'a> Deserialize<'a>
+ Debug
+ Send
+ Sync
+ Clone;
type Error: Error;
type InitData;
fn init_config(&self, d: Self::InitData) -> Result<RunnerConfig<Self>, Self::Error>;
}
pub trait ProviderCall {
type Provider: Provider<Function = Self>;
fn call(
&self,
args: &[&<Self::Provider as Provider>::Value],
) -> Result<Option<<Self::Provider as Provider>::Value>, <Self::Provider as Provider>::Error>;
}
pub trait ProviderDeserialize {
type Provider: Provider<Value = Self>;
// fn de_into<T: for Deserialize>(&self) -> Result<T, <Self::Provider as Provider>::Error>;
fn de_into<T>(&self) -> Result<T, <Self::Provider as Provider>::Error>;
}
pub trait ProviderSerialize {
type Provider: Provider<Value = Self>;
// fn de_into<T: for Deserialize>(&self) -> Result<T, <Self::Provider as Provider>::Error>;
fn se_from<T: Serialize>(from: &T) -> Result<Self, <Self::Provider as Provider>::Error>
where
Self: Sized;
}

View File

@ -0,0 +1,10 @@
use crate::config::result::ConfigResult;
use super::Provider;
pub trait ResolveValue {
type Value;
type Runtime: Provider;
fn resolve(self) -> ConfigResult<Self::Value>;
}

View File

@ -253,6 +253,17 @@ pub trait CallDB {
Ok(users.find(doc! {}).await?.try_collect().await?) Ok(users.find(doc! {}).await?.try_collect().await?)
} }
async fn get_users_by_ids(&self, ids: Vec<i64>) -> DbResult<Vec<User>> {
let db = self.get_database_immut().await;
let users = db.collection::<User>("users");
Ok(users
.find(doc! {"id": {"$in": ids}})
.await?
.try_collect()
.await?)
}
async fn get_random_users(&self, n: u32) -> DbResult<Vec<User>> { async fn get_random_users(&self, n: u32) -> DbResult<Vec<User>> {
let db = self.get_database_immut().await; let db = self.get_database_immut().await;
let users = db.collection::<User>("users"); let users = db.collection::<User>("users");

View File

@ -3,15 +3,19 @@ pub mod bot_handler;
pub mod bot_manager; pub mod bot_manager;
pub mod botscript; pub mod botscript;
pub mod commands; pub mod commands;
pub mod config;
pub mod db; pub mod db;
pub mod handlers; pub mod handlers;
pub mod message_answerer; pub mod message_answerer;
pub mod mongodb_storage; pub mod mongodb_storage;
pub mod runtimes;
pub mod utils; pub mod utils;
use bot_manager::BotManager; use bot_manager::BotManager;
use botscript::application::attach_user_application; use botscript::application::attach_user_application;
use botscript::{Runner, RunnerConfig, ScriptError, ScriptResult}; use botscript::{Runner, ScriptError, ScriptResult};
use config::result::ConfigError;
use config::{Provider, RunnerConfig};
use db::application::Application; use db::application::Application;
use db::bots::BotInstance; use db::bots::BotInstance;
use db::callback_info::CallbackInfo; use db::callback_info::CallbackInfo;
@ -91,11 +95,11 @@ pub struct BotController {
pub runtime: Arc<Mutex<BotRuntime>>, pub runtime: Arc<Mutex<BotRuntime>>,
} }
pub struct BotRuntime { pub struct BotRuntime<P: Provider> {
pub rc: RunnerConfig, pub rc: RunnerConfig<P>,
pub runner: Runner, pub runner: Runner,
} }
unsafe impl Send for BotRuntime {} unsafe impl<P: Provider> Send for BotRuntime<P> {}
impl Drop for BotController { impl Drop for BotController {
fn drop(&mut self) { fn drop(&mut self) {
@ -126,7 +130,7 @@ impl BotController {
let bot = Bot::new(token); let bot = Bot::new(token);
let mut runner = Runner::init_with_db(&mut db)?; let mut runner = Runner::init_with_db(&mut db)?;
runner.call_attacher(|c, o| attach_user_application(c, o, db.clone(), bot.clone()))??; // runner.call_attacher(|c, o| attach_user_application(c, o, db.clone(), bot.clone()))??;
let rc = runner.init_config(script)?; let rc = runner.init_config(script)?;
let runtime = Arc::new(Mutex::new(BotRuntime { rc, runner })); let runtime = Arc::new(Mutex::new(BotRuntime { rc, runner }));
@ -147,6 +151,7 @@ pub enum BotError {
IoError(#[from] std::io::Error), IoError(#[from] std::io::Error),
RwLockError(String), RwLockError(String),
MAError(#[from] MessageAnswererError), MAError(#[from] MessageAnswererError),
ConfigError(#[from] ConfigError),
} }
pub type BotResult<T> = Result<T, BotError>; pub type BotResult<T> = Result<T, BotError>;

33
src/runtimes/mlua/mod.rs Normal file
View File

@ -0,0 +1,33 @@
use mlua::{Error, Function, Lua, Value};
use crate::config::Provider;
#[derive(Clone)]
pub struct LuaRuntime {
lua: Lua,
}
impl LuaRuntime {
pub fn new() -> Self {
let lua = Lua::new();
Self { lua }
}
}
pub struct LuaInit {
config: String,
}
impl Provider for LuaRuntime {
type Function = Function;
type Value = Value;
type Error = Error;
type InitData = LuaInit;
fn init_config(&self, d: Self::InitData) -> Result<crate::config::RunnerConfig<Self>, Self::Error> {
todo!()
}
}

2
src/runtimes/mod.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod v8;
// pub mod mlua;

284
src/runtimes/v8/mod.rs Normal file
View File

@ -0,0 +1,284 @@
mod value_replace;
use std::{
collections::HashMap,
marker::PhantomData,
ops::{Deref, DerefMut},
sync::{
mpsc::{Receiver, Sender},
Arc, Mutex, RwLock,
},
thread::JoinHandle,
};
use crate::config::{
traits::{ProviderCall, ProviderDeserialize, ProviderSerialize},
Provider, RunnerConfig,
};
use deno_core::{ascii_str, error::CoreError, FastString, JsRuntime, RuntimeOptions};
use serde::{Deserialize, Serialize};
use serde_v8::{from_v8, Value as SerdeValue};
use v8::{Context, ContextScope, Function, HandleScope, Local, OwnedIsolate};
enum EventType {
GetScriptConfig(String),
ExecuteFunction(V8Function, Vec<V8Value>),
}
pub struct Event {
event: EventType,
runtime: Arc<V8Runtime>,
}
enum RuntimeReturn {
Value(V8Value),
OptionalValue(Option<V8Value>),
Config(RunnerConfig<V8Runtime>),
}
impl RuntimeReturn {
fn as_value(self) -> Option<V8Value> {
if let Self::Value(v) = self {
Some(v)
} else {
None
}
}
fn as_optional_value(self) -> Option<Option<V8Value>> {
if let Self::OptionalValue(v) = self {
Some(v)
} else {
None
}
}
fn as_config(self) -> Option<RunnerConfig<V8Runtime>> {
if let Self::Config(v) = self {
Some(v)
} else {
None
}
}
}
#[derive(Clone, Serialize, Deserialize)]
pub struct V8Runtime {
#[serde(skip, default = "default_runtime")]
runtime: Arc<Mutex<JoinHandle<()>>>,
#[serde(skip, default = "default_sender")]
tx: Sender<Event>,
#[serde(skip, default = "default_receiver")]
rx: Arc<Mutex<Receiver<RuntimeReturn>>>,
}
fn default_runtime() -> Arc<Mutex<JoinHandle<()>>> {
todo!()
}
fn default_sender() -> Sender<Event> {
todo!()
}
fn default_receiver() -> Arc<Mutex<Receiver<RuntimeReturn>>> {
todo!()
}
impl Default for V8Runtime {
fn default() -> Self {
Self::new()
}
}
impl V8Runtime {
pub fn new() -> Self {
let (tx, rx) = std::sync::mpsc::channel::<Event>();
let (rtx, rrx) = std::sync::mpsc::channel::<RuntimeReturn>();
let thread = std::thread::spawn(move || {
let options = RuntimeOptions::default();
let mut runtime = JsRuntime::new(options);
let handlers: HashMap<&str, v8::Local<'_, v8::Value>> = HashMap::new();
loop {
let event = match rx.recv() {
Ok(event) => event,
Err(err) => break,
};
match event {
Event::GetScriptConfig(script) => {
let code = FastString::from(script);
let result = runtime.execute_script("", code).unwrap();
let mut scope = runtime.handle_scope();
let result = Local::new(&mut scope, result);
value_replace::replace(&mut result, &mut runtime, &mut handlers);
let config: RunnerConfig<Self> = from_v8(&mut scope, result).unwrap();
// rtx.send(RuntimeReturn::Value(unsafe { V8Value::new(SerdeValue::from(result)) }))
rtx.send(RuntimeReturn::Config(config)).unwrap();
}
Event::ExecuteFunction(f, args) => {
let value = unsafe { f.get_inner() }.get_value();
let value = handlers[value];
let mut scope = runtime.handle_scope();
let context = Local::new(&mut scope, runtime.main_context());
let global = context.global(&mut scope).into();
let f: Local<'_, Function> = value.try_into().unwrap();
let args: Vec<Local<'_, v8::Value>> = args
.into_iter()
.map(|a| unsafe {
let r = a.get_inner().get_value();
r
})
.collect();
let result = f.call(&mut scope, global, args.as_slice());
let result = result.map(|r| SerdeValue::from(r));
rtx.send(RuntimeReturn::OptionalValue(
result.map(|result| unsafe { V8Value::new(SerdeValue::from(result)) }),
))
.unwrap();
}
};
}
});
Self {
runtime: Arc::new(Mutex::new(thread)),
tx,
rx: Arc::new(Mutex::new(rrx)),
}
}
pub(crate) fn call_event(&self, event: Event) -> RuntimeReturn {
// locking before send to avoid runtime output shuffle
// because reciever depends on sender
// and runtime single-threaded anyway
let rx = self.rx.lock().unwrap();
self.tx.send(event).unwrap();
rx.recv().unwrap()
}
}
#[derive(thiserror::Error, Debug)]
pub enum V8Error {
#[error("v8 data error: {0:?}")]
DataError(#[from] v8::DataError),
#[error("Failed to create v8 string: {0:?}")]
StringCreation(String),
#[error("Deno core error: {0:?}")]
DenoCore(#[from] CoreError),
#[error("error context: {0:?}")]
Other(String),
}
pub struct V8Init {
code: String,
}
#[derive(Clone, Serialize, Deserialize)]
pub struct V8Value {
value: ValueHandler,
runtime: Arc<V8Runtime>,
}
#[derive(Clone, Serialize, Deserialize)]
pub struct ValueHandler {
value: String,
}
impl ValueHandler {
fn get_value(&self) -> &str {
&self.value
}
}
impl V8Value {
unsafe fn get_inner(&self) -> &ValueHandler {
&self.value
}
unsafe fn new(runtime: Arc<V8Runtime>, value: ValueHandler) -> Self {
Self { runtime, value }
}
}
impl ProviderDeserialize for V8Value {
type Provider = V8Runtime;
fn de_into<T>(&self) -> Result<T, <Self::Provider as Provider>::Error> {
todo!()
}
}
impl ProviderSerialize for V8Value {
type Provider = V8Runtime;
fn se_from<T: Serialize>(from: &T) -> Result<Self, <Self::Provider as Provider>::Error>
where
Self: Sized,
{
todo!()
}
}
impl std::fmt::Debug for V8Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("V8Value")
.field("value", &"_".to_string())
.finish()
}
}
#[derive(Clone, Serialize, Deserialize)]
pub struct V8Function {
value: ValueHandler,
runtime: Arc<Mutex<V8Runtime>>,
}
impl V8Function {
unsafe fn get_inner(&self) -> &ValueHandler {
&self.value
}
}
impl ProviderCall for V8Function {
type Provider = V8Runtime;
fn call(
&self,
args: &[&<Self::Provider as Provider>::Value],
) -> Result<Option<<Self::Provider as Provider>::Value>, <Self::Provider as Provider>::Error>
{
let result: RuntimeReturn =
self.runtime
.lock()
.unwrap()
.call_event(Event::ExecuteFunction(
self.clone(),
args.into_iter().map(|v| (*v).clone()).collect(),
));
Ok(result.as_optional_value().unwrap())
}
}
impl std::fmt::Debug for V8Function {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("V8Value")
.field("value", &"_".to_string())
.finish()
}
}
impl Provider for V8Runtime {
type Function = V8Function;
type Value = V8Value;
type Error = V8Error;
type InitData = V8Init;
fn init_config(&self, d: Self::InitData) -> Result<RunnerConfig<Self>, Self::Error> {
let result = self.call_event(Event::GetScriptConfig(d.code));
let value = result.as_config().unwrap();
Ok(value)
}
}

View File

@ -0,0 +1,13 @@
use std::collections::HashMap;
use deno_core::JsRuntime;
use v8::{Local, Value};
/// move out unsupported by serde types to map, leaving key instead of value to get this value
pub(crate) fn replace(
value: &mut Local<'_, Value>,
runtime: &mut JsRuntime,
outmap: &mut HashMap<String, Local<'_, Value>>,
) {
todo!()
}