diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..352a6265 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "rust-analyzer.linkedProjects": [ + "./Cargo.toml" + ] +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index ff46229a..456c4f5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,37 @@ version = 3 [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ "memchr", ] [[package]] -name = "autocfg" -version = "1.0.1" +name = "atom_syndication" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "ca96cb38e3d8236f1573a84bbc55e130bd1ae07df770e36d0cf221ea7a50e36c" +dependencies = [ + "chrono", + "derive_builder", + "diligent-date-parser", + "never", + "quick-xml", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c70beb79cbb5ce9c4f8e20849978f34225931f665bb49efa6982875a4d5facb3" [[package]] name = "block-buffer" @@ -46,9 +65,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "bytemuck" -version = "1.7.3" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" [[package]] name = "byteorder" @@ -56,6 +75,22 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[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.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "contrast" version = "0.1.0" @@ -68,18 +103,87 @@ dependencies = [ [[package]] name = "convert_case" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] [[package]] name = "ctor" -version = "0.1.21" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" +checksum = "dd4056f63fce3b82d852c3da92b08ea59959890813a7f4ce9c0ff85b10cf301b" dependencies = [ "quote", - "syn", + "syn 2.0.14", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", ] [[package]] @@ -92,12 +196,35 @@ dependencies = [ ] [[package]] -name = "form_urlencoded" -version = "1.0.1" +name = "diligent-date-parser" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +checksum = "f6cf7fe294274a222363f84bcb63cdea762979a0443b4cf1f4f8fd17c86b1182" +dependencies = [ + "chrono", +] + +[[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" dependencies = [ - "matches", "percent-encoding", ] @@ -117,33 +244,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -name = "idna" -version = "0.2.3" +name = "ident_case" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" dependencies = [ - "matches", "unicode-bidi", "unicode-normalization", ] [[package]] name = "itoa" -version = "1.0.1" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] -name = "lazy_static" -version = "1.4.0" +name = "libloading" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] [[package]] name = "matrix-hookshot" @@ -156,6 +286,7 @@ dependencies = [ "napi-build", "napi-derive", "rgb", + "rss", "serde", "serde_derive", "serde_json", @@ -175,22 +306,23 @@ dependencies = [ [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "napi" -version = "2.0.2" +version = "2.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cfe7fef533df6323a5aa17d75cb162850f2b045adabb9922bfbd234426a1bb" +checksum = "556470a21074b55be8adee5f27ca04389cfdaca323a28b4b0e9c15466de94731" dependencies = [ + "bitflags", "ctor", - "lazy_static", + "napi-derive", "napi-sys", + "once_cell", "serde", "serde_json", - "windows", ] [[package]] @@ -201,51 +333,71 @@ checksum = "ebd4419172727423cf30351406c54f6cc1b354a2cfb4f1dba3e6cd07f6d5522b" [[package]] name = "napi-derive" -version = "2.0.4" +version = "2.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb47b1f5f021abe96fcb84e7977f46c0aa645904c18cdb7b3a031e61899bf48" +checksum = "af2ac63101a19228b0881694cac07468d642fd10e4f943a9c9feebeebf1a4787" dependencies = [ "convert_case", "napi-derive-backend", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "napi-derive-backend" -version = "1.0.21" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487c39117657211e9bf93acade9363eac61ceead142e4906d15ff08d29fa448d" +checksum = "0e32b5bc4d803e40b783b0aa3fe488eac8711cfaa4c5c9915293dfd3d0b99925" dependencies = [ "convert_case", "once_cell", "proc-macro2", "quote", "regex", - "syn", + "semver", + "syn 1.0.109", ] [[package]] name = "napi-sys" -version = "2.1.0" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a385494dac3c52cbcacb393bb3b42669e7db8ab240c7ad5115f549eb061f2cc" +checksum = "166b5ef52a3ab5575047a9fe8d4a030cdd0f63c96f071cd6907674453b07bae3" +dependencies = [ + "libloading", +] + +[[package]] +name = "never" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96aba5aa877601bb3f6dd6a63a969e1f82e60646e81e71b14496995e9853c91" + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", ] [[package]] name = "once_cell" -version = "1.9.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "opaque-debug" @@ -255,33 +407,43 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "percent-encoding" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ - "unicode-xid", + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5c1a97b1bc42b1d550bfb48d4262153fe400a12bab1511821736f7eac76d7e2" +dependencies = [ + "encoding_rs", + "memchr", ] [[package]] name = "quote" -version = "1.0.14" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] [[package]] name = "regex" -version = "1.5.6" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" dependencies = [ "aho-corasick", "memchr", @@ -290,47 +452,65 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.26" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "rgb" -version = "0.8.31" +version = "0.8.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a374af9a0e5fdcdd98c1c7b64f05004f9ea2555b6c75f211daa81268a3c50f1" +checksum = "20ec2d3e3fc7a92ced357df9cebd5a10b6fb2aa1ee797bf7e9ce2f17dffc8f59" dependencies = [ "bytemuck", ] [[package]] -name = "ryu" -version = "1.0.9" +name = "rss" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +checksum = "aa1ec965a5f5ec71e16106b35df21861c4014ace848c6b75720816925552936d" +dependencies = [ + "atom_syndication", + "derive_builder", + "never", + "quick-xml", +] + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.132" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" [[package]] name = "serde_derive" -version = "1.0.132" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.14", ] [[package]] name = "serde_json" -version = "1.0.73" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" +checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" dependencies = [ "itoa", "ryu", @@ -338,109 +518,110 @@ dependencies = [ ] [[package]] -name = "syn" -version = "1.0.84" +name = "strsim" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] name = "tinyvec" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "typenum" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "unicode-bidi" -version = "0.3.7" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-normalization" -version = "0.1.19" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] [[package]] -name = "unicode-xid" -version = "0.2.2" +name = "unicode-segmentation" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "url" -version = "2.2.2" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" dependencies = [ "form_urlencoded", "idna", - "matches", "percent-encoding", ] [[package]] -name = "windows" -version = "0.29.0" +name = "winapi" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac7fef12f4b59cd0a29339406cc9203ab44e440ddff6b3f5a41455349fa9cf3" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] -name = "windows_aarch64_msvc" -version = "0.29.0" +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d027175d00b01e0cbeb97d6ab6ebe03b12330a35786cbaca5252b1c4bf5d9b" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] -name = "windows_i686_gnu" -version = "0.29.0" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8793f59f7b8e8b01eda1a652b2697d87b93097198ae85f823b969ca5b89bba58" - -[[package]] -name = "windows_i686_msvc" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8602f6c418b67024be2996c512f5f995de3ba417f4c75af68401ab8756796ae4" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d615f419543e0bd7d2b3323af0d86ff19cbc4f816e6453f36a2c2ce889c354" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d95421d9ed3672c280884da53201a5c46b7b2765ca6faf34b0d71cf34a3561" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 71e5ee51..9a4af331 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ contrast = "0" rgb = "0" md-5 = "0.8.0" hex = "0.4.3" - +rss = "2.0.3" [build-dependencies] napi-build = "1" diff --git a/changelog.d/709.misc b/changelog.d/709.misc new file mode 100644 index 00000000..83377c9c --- /dev/null +++ b/changelog.d/709.misc @@ -0,0 +1 @@ +Switch to using Rust for parsing RSS feeds. \ No newline at end of file diff --git a/src/Connections/GithubRepo.ts b/src/Connections/GithubRepo.ts index d6ce2f2f..698c8512 100644 --- a/src/Connections/GithubRepo.ts +++ b/src/Connections/GithubRepo.ts @@ -2,7 +2,7 @@ import { Appservice, Intent, IRichReplyMetadata, StateEvent } from "matrix-bot-sdk"; import { BotCommands, botCommand, compileBotCommands, HelpFunction } from "../BotCommands"; import { CommentProcessor } from "../CommentProcessor"; -import { FormatUtil } from "../FormatUtil"; +import { FormatUtil, LooseMinimalGitHubRepo } from "../FormatUtil"; import { Octokit } from "@octokit/rest"; import { Connection, IConnection, IConnectionState, InstantiateConnectionOpts, ProvisionConnectionOpts } from "./IConnection"; import { GetConnectionsResponseItem } from "../provisioning/api"; @@ -25,7 +25,7 @@ import { GitHubIssueConnection } from "./GithubIssue"; import { BridgeConfigGitHub } from "../Config/Config"; import { ApiError, ErrCode, ValidatorApiError } from "../api"; import { PermissionCheckFn } from "."; -import { GitHubRepoMessageBody, MinimalGitHubIssue, MinimalGitHubRepo } from "../libRs"; +import { GitHubRepoMessageBody, MinimalGitHubIssue } from "../libRs"; import Ajv, { JSONSchemaType } from "ajv"; import { HookFilter } from "../HookFilter"; import { GitHubGrantChecker } from "../Github/GrantChecker"; @@ -637,7 +637,7 @@ export class GitHubRepoConnection extends CommandConnection(accountDataSchema); -function isNonEmptyString(input: any): input is string { - return input && typeof input === 'string'; +function isNonEmptyString(input: unknown): input is string { + return Boolean(input) && typeof input === 'string'; } function stripHtml(input: string): string { @@ -108,11 +109,6 @@ function shuffle(array: T[]): T[] { return array; } -interface FeedItem { - title?: string; - link?: string; - id?: string; -} export class FeedReader { private static buildParser(): Parser { @@ -131,7 +127,6 @@ export class FeedReader { url: string, headers: Record, timeoutMs: number, - parser: Parser = FeedReader.buildParser(), httpClient = axios, ): Promise<{ response: AxiosResponse, feed: Parser.Output }> { const response = await httpClient.get(url, { @@ -142,7 +137,11 @@ export class FeedReader { // We don't want to wait forever for the feed. timeout: timeoutMs, }); - const feed = await parser.parseString(response.data); + + if (typeof response.data !== "string") { + throw Error('Unexpected response type'); + } + const feed = parseRSSFeed(response.data); return { response, feed }; } @@ -151,16 +150,16 @@ export class FeedReader { * @param item A feed item. * @returns Return either a link to the item, or null. */ - private static parseLinkFromItem(item: {guid?: string, link?: string}) { + private static parseLinkFromItem(item: FeedItem) { if (item.link) { return item.link; } - if (item.guid) { + if (item.id && item.idIsPermalink) { try { // The feed librray doesn't give us attributes (needs isPermaLink), so we're not really sure if this a URL or not. // Parse it and see. // https://validator.w3.org/feed/docs/rss2.html#ltguidgtSubelementOfLtitemgt - const url = new URL(item.guid); + const url = new URL(item.id); return url.toString(); } catch (ex) { return null; @@ -298,7 +297,6 @@ export class FeedReader { }, // We don't want to wait forever for the feed. this.config.pollTimeoutSeconds * 1000, - this.parser, this.httpClient, ); @@ -327,7 +325,7 @@ export class FeedReader { for (const item of feed.items) { // Find the first guid-like that looks like a string. // Some feeds have a nasty habit of leading a empty tag there, making us parse it as garbage. - const guid = [item.guid, item.id, item.link, item.title].find(isNonEmptyString); + const guid = [item.id, item.link, item.title].find(isNonEmptyString); if (!guid) { log.error(`Could not determine guid for entry in ${url}, skipping`); continue; @@ -352,7 +350,7 @@ export class FeedReader { title: isNonEmptyString(item.title) ? stripHtml(item.title) : null, pubdate: item.pubDate ?? null, summary: item.summary ?? null, - author: item.creator ?? null, + author: item.author ?? null, link: FeedReader.parseLinkFromItem(item), fetchKey }; diff --git a/src/feeds/mod.rs b/src/feeds/mod.rs new file mode 100644 index 00000000..67c567fa --- /dev/null +++ b/src/feeds/mod.rs @@ -0,0 +1 @@ +pub mod parser; diff --git a/src/feeds/parser.rs b/src/feeds/parser.rs new file mode 100644 index 00000000..671fa233 --- /dev/null +++ b/src/feeds/parser.rs @@ -0,0 +1,65 @@ +use std::str::FromStr; + +use napi::bindgen_prelude::{Error as JsError, Status}; +use rss::{Channel, Error as RssError}; + +#[derive(Serialize, Debug, Deserialize)] +#[napi(object)] +pub struct FeedItem { + pub title: Option, + pub link: Option, + pub id: Option, + pub id_is_permalink: bool, + pub pubdate: Option, + pub summary: Option, + pub author: Option, +} + +#[derive(Serialize, Debug, Deserialize)] +#[napi(object)] +pub struct JsRssChannel { + pub title: String, + pub items: Vec, +} +#[napi(js_name = "parseRSSFeed")] +pub fn js_parse_rss_feed(xml: String) -> Result { + fn map_item_value(original: &str) -> String { + original.to_string() + } + + Channel::from_str(&xml) + .map(|channel| JsRssChannel { + title: channel.title().to_string(), + items: channel + .items() + .iter() + .map(|item| FeedItem { + title: item.title().map(map_item_value), + link: item.link().map(map_item_value), + id: item.guid().map(|f| f.value().to_string()), + id_is_permalink: item.guid().map_or(false, |f| f.is_permalink()), + pubdate: item.pub_date().map(map_item_value), + summary: item.description().map(map_item_value), + author: item.author().map(map_item_value), + }) + .collect(), + }) + .map_err(|op| match op { + RssError::Utf8(err) => JsError::new( + Status::Unknown, + format!("An error while converting bytes to UTF8. {}'", err).to_string(), + ), + RssError::Xml(err) => JsError::new( + Status::Unknown, + format!("XML parsing error. {}", err).to_string(), + ), + RssError::InvalidStartTag => JsError::new( + Status::Unknown, + format!("The input didn't begin with an opening tag.").to_string(), + ), + err => JsError::new( + Status::Unknown, + format!("Unknown error trying to parse feed parse feed '{}'", err).to_string(), + ), + }) +} diff --git a/src/lib.rs b/src/lib.rs index 7cf91108..a0a5002e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ pub mod Config; pub mod Github; pub mod Jira; +pub mod feeds; pub mod format_util; #[macro_use]