Persist links to a database
This commit is contained in:
parent
17fb0c1856
commit
b157985bf3
10 changed files with 451 additions and 44 deletions
266
Cargo.lock
generated
266
Cargo.lock
generated
|
|
@ -147,9 +147,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.22.0"
|
version = "1.23.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540"
|
checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
|
|
@ -159,9 +159,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.19"
|
version = "1.2.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
|
checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
|
|
@ -174,9 +174,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.40"
|
version = "0.4.41"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
|
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android-tzdata",
|
"android-tzdata",
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
|
|
@ -189,9 +189,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.32"
|
version = "4.5.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83"
|
checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
|
|
@ -199,9 +199,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.32"
|
version = "4.5.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8"
|
checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
|
|
@ -276,6 +276,95 @@ version = "0.8.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling"
|
||||||
|
version = "0.20.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"darling_macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_core"
|
||||||
|
version = "0.20.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"ident_case",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"strsim",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_macro"
|
||||||
|
version = "0.20.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "deranged"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
|
||||||
|
dependencies = [
|
||||||
|
"powerfmt",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diesel"
|
||||||
|
version = "2.2.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ff3e1edb1f37b4953dd5176916347289ed43d7119cc2e6c7c3f7849ff44ea506"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"diesel_derives",
|
||||||
|
"libsqlite3-sys",
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diesel_derives"
|
||||||
|
version = "2.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68d4216021b3ea446fd2047f5c8f8fe6e98af34508a254a01e4d6bc1e844f84d"
|
||||||
|
dependencies = [
|
||||||
|
"diesel_table_macro_syntax",
|
||||||
|
"dsl_auto_type",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diesel_migrations"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a73ce704bad4231f001bff3314d91dce4aba0770cee8b233991859abc15c1f6"
|
||||||
|
dependencies = [
|
||||||
|
"diesel",
|
||||||
|
"migrations_internals",
|
||||||
|
"migrations_macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diesel_table_macro_syntax"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25"
|
||||||
|
dependencies = [
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "directories"
|
name = "directories"
|
||||||
version = "6.0.0"
|
version = "6.0.0"
|
||||||
|
|
@ -308,6 +397,26 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dsl_auto_type"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "139ae9aca7527f85f26dd76483eb38533fd84bd571065da1739656ef71c5ff5b"
|
||||||
|
dependencies = [
|
||||||
|
"darling",
|
||||||
|
"either",
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.8.35"
|
version = "0.8.35"
|
||||||
|
|
@ -359,7 +468,7 @@ dependencies = [
|
||||||
"pear",
|
"pear",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"toml 0.8.20",
|
"toml",
|
||||||
"uncased",
|
"uncased",
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
@ -715,6 +824,12 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ident_case"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
|
|
@ -808,6 +923,16 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libsqlite3-sys"
|
||||||
|
version = "0.33.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "947e6816f7825b2b45027c2c32e7085da9934defa535de4a6a46b10a4d5257fa"
|
||||||
|
dependencies = [
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
|
|
@ -843,6 +968,27 @@ version = "2.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "migrations_internals"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fd01039851e82f8799046eabbb354056283fb265c8ec0996af940f4e85a380ff"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"toml",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "migrations_macros"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ffb161cc72176cb37aa47f1fc520d3ef02263d67d661f44f05d05a079e1237fd"
|
||||||
|
dependencies = [
|
||||||
|
"migrations_internals",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mime"
|
name = "mime"
|
||||||
version = "0.3.17"
|
version = "0.3.17"
|
||||||
|
|
@ -895,6 +1041,12 @@ dependencies = [
|
||||||
"tempfile",
|
"tempfile",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-conv"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.19"
|
version = "0.2.19"
|
||||||
|
|
@ -915,9 +1067,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.21.1"
|
version = "1.21.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
|
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl"
|
name = "openssl"
|
||||||
|
|
@ -1023,10 +1175,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "powerfmt"
|
||||||
version = "1.0.94"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
|
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.95"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
@ -1066,6 +1224,8 @@ dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"color-eyre",
|
"color-eyre",
|
||||||
|
"diesel",
|
||||||
|
"diesel_migrations",
|
||||||
"directories",
|
"directories",
|
||||||
"figment",
|
"figment",
|
||||||
"figment_file_provider_adapter",
|
"figment_file_provider_adapter",
|
||||||
|
|
@ -1074,9 +1234,8 @@ dependencies = [
|
||||||
"regex",
|
"regex",
|
||||||
"roux",
|
"roux",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"tempfile",
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml 0.5.11",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1350,9 +1509,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.100"
|
version = "2.0.101"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
|
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -1440,6 +1599,37 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.3.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
|
||||||
|
dependencies = [
|
||||||
|
"deranged",
|
||||||
|
"itoa",
|
||||||
|
"num-conv",
|
||||||
|
"powerfmt",
|
||||||
|
"serde",
|
||||||
|
"time-core",
|
||||||
|
"time-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-core"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-macros"
|
||||||
|
version = "0.2.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
|
||||||
|
dependencies = [
|
||||||
|
"num-conv",
|
||||||
|
"time-core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinystr"
|
name = "tinystr"
|
||||||
version = "0.7.6"
|
version = "0.7.6"
|
||||||
|
|
@ -1489,9 +1679,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-util"
|
name = "tokio-util"
|
||||||
version = "0.7.14"
|
version = "0.7.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034"
|
checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
|
@ -1502,18 +1692,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.5.11"
|
version = "0.8.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
|
checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae"
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "toml"
|
|
||||||
version = "0.8.20"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
|
|
@ -1523,26 +1704,33 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.6.8"
|
version = "0.6.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
|
checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.22.24"
|
version = "0.22.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
|
checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
|
"toml_write",
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_write"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower-service"
|
name = "tower-service"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
|
@ -1972,9 +2160,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.7.6"
|
version = "0.7.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10"
|
checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,6 @@ clap = { version = "4.5.32", features = ["derive"] }
|
||||||
roux = "2.2.14"
|
roux = "2.2.14"
|
||||||
figment = { version = "0.10", features = ["toml", "json", "env"] }
|
figment = { version = "0.10", features = ["toml", "json", "env"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
|
||||||
toml = "0.5"
|
|
||||||
tokio = { version = "1.44.2", features = ["rt", "rt-multi-thread", "macros"] }
|
tokio = { version = "1.44.2", features = ["rt", "rt-multi-thread", "macros"] }
|
||||||
regex = "1.10.3"
|
regex = "1.10.3"
|
||||||
figment_file_provider_adapter = "0.1.1"
|
figment_file_provider_adapter = "0.1.1"
|
||||||
|
|
@ -22,3 +20,6 @@ log = "0.4.27"
|
||||||
color-eyre = "0.6.3"
|
color-eyre = "0.6.3"
|
||||||
chrono = { version = "0.4", features = ["serde"] }
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
multimap = "0.10.0"
|
multimap = "0.10.0"
|
||||||
|
diesel = { version = "2.2.10", features = ["sqlite", "chrono"] }
|
||||||
|
diesel_migrations = "2.2.0"
|
||||||
|
tempfile = "3.19.1"
|
||||||
|
|
|
||||||
9
diesel.toml
Normal file
9
diesel.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
# For documentation on how to configure this file,
|
||||||
|
# see https://diesel.rs/guides/configuring-diesel-cli
|
||||||
|
|
||||||
|
[print_schema]
|
||||||
|
file = "src/schema.rs"
|
||||||
|
custom_type_derives = ["diesel::query_builder::QueryId", "Clone"]
|
||||||
|
|
||||||
|
[migrations_directory]
|
||||||
|
dir = "./migrations"
|
||||||
|
|
@ -32,13 +32,16 @@
|
||||||
name = "reddit-magnet";
|
name = "reddit-magnet";
|
||||||
buildInputs = with pkgs; [
|
buildInputs = with pkgs; [
|
||||||
cargo
|
cargo
|
||||||
|
cargo-edit
|
||||||
cargo-machete
|
cargo-machete
|
||||||
cargo-release
|
cargo-release
|
||||||
cargo-sort
|
cargo-sort
|
||||||
|
diesel-cli
|
||||||
openssl
|
openssl
|
||||||
pkg-config
|
pkg-config
|
||||||
rustc
|
rustc
|
||||||
rust-toolchain
|
rust-toolchain
|
||||||
|
sqlite
|
||||||
] ++ lib.optionals stdenv.isDarwin [
|
] ++ lib.optionals stdenv.isDarwin [
|
||||||
libiconv
|
libiconv
|
||||||
darwin.apple_sdk.frameworks.SystemConfiguration
|
darwin.apple_sdk.frameworks.SystemConfiguration
|
||||||
|
|
|
||||||
1
migrations/2025-04-29-035819_create_magnets/down.sql
Normal file
1
migrations/2025-04-29-035819_create_magnets/down.sql
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
DROP TABLE magnets
|
||||||
9
migrations/2025-04-29-035819_create_magnets/up.sql
Normal file
9
migrations/2025-04-29-035819_create_magnets/up.sql
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
CREATE TABLE magnets
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
title VARCHAR NOT NULL,
|
||||||
|
submitter VARCHAR NOT NULL,
|
||||||
|
subreddit VARCHAR NOT NULL,
|
||||||
|
link VARCHAR NOT NULL,
|
||||||
|
published_at DATETIME NOT NULL
|
||||||
|
)
|
||||||
123
src/db.rs
Normal file
123
src/db.rs
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
use crate::models::{Magnet, NewMagnet};
|
||||||
|
use crate::schema::magnets;
|
||||||
|
use crate::PostInfo;
|
||||||
|
use color_eyre::eyre::{eyre, Result, WrapErr};
|
||||||
|
use diesel::prelude::*;
|
||||||
|
use diesel::sqlite::SqliteConnection;
|
||||||
|
use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};
|
||||||
|
use std::fs::create_dir_all;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations");
|
||||||
|
|
||||||
|
/// Database for storing magnet links and associated information
|
||||||
|
pub struct Database {
|
||||||
|
conn: SqliteConnection,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::PostInfo;
|
||||||
|
use chrono::Utc;
|
||||||
|
use tempfile::tempdir;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_database_initialization() {
|
||||||
|
let temp_dir = tempdir().unwrap();
|
||||||
|
let db_path = temp_dir.path().join("test.db");
|
||||||
|
|
||||||
|
let db = Database::new(&db_path);
|
||||||
|
assert!(db.is_ok());
|
||||||
|
|
||||||
|
assert!(db_path.exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_store_and_retrieve_magnet_links() {
|
||||||
|
let temp_dir = tempdir().unwrap();
|
||||||
|
let db_path = temp_dir.path().join("test.db");
|
||||||
|
|
||||||
|
let mut db = Database::new(&db_path).unwrap();
|
||||||
|
|
||||||
|
let post_info = PostInfo {
|
||||||
|
title: "Test Title".to_string(),
|
||||||
|
submitter: "test_user".to_string(),
|
||||||
|
subreddit: "test_subreddit".to_string(),
|
||||||
|
magnet_links: vec![
|
||||||
|
"magnet:?xt=urn:btih:test1".to_string(),
|
||||||
|
"magnet:?xt=urn:btih:test2".to_string(),
|
||||||
|
],
|
||||||
|
timestamp: Utc::now(),
|
||||||
|
};
|
||||||
|
let expected_timestamp = post_info.timestamp.naive_utc();
|
||||||
|
|
||||||
|
let result = db.store_magnets(&post_info);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
|
||||||
|
let magnets = db.get_all_magnets().unwrap();
|
||||||
|
assert_eq!(magnets.len(), 2);
|
||||||
|
|
||||||
|
for magnet in magnets {
|
||||||
|
assert!(
|
||||||
|
magnet.link == "magnet:?xt=urn:btih:test1"
|
||||||
|
|| magnet.link == "magnet:?xt=urn:btih:test2"
|
||||||
|
);
|
||||||
|
assert_eq!(magnet.title, "Test Title");
|
||||||
|
assert_eq!(magnet.submitter, "test_user");
|
||||||
|
assert_eq!(magnet.subreddit, "test_subreddit");
|
||||||
|
assert_eq!(magnet.published_at, expected_timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Database {
|
||||||
|
pub fn new<P: AsRef<Path>>(path: P) -> Result<Self> {
|
||||||
|
let database_url = path
|
||||||
|
.as_ref()
|
||||||
|
.to_str()
|
||||||
|
.ok_or_else(|| eyre!("Database path is not valid UTF-8"))?;
|
||||||
|
|
||||||
|
if let Some(parent) = path.as_ref().parent() {
|
||||||
|
create_dir_all(parent)
|
||||||
|
.wrap_err_with(|| format!("Failed to create directory: {:?}", parent))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut conn = SqliteConnection::establish(database_url)
|
||||||
|
.wrap_err("Failed to open database connection")?;
|
||||||
|
|
||||||
|
conn.run_pending_migrations(MIGRATIONS)
|
||||||
|
.expect("Failed to apply database migrations");
|
||||||
|
|
||||||
|
Ok(Database { conn })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_all_magnets(&mut self) -> Result<Vec<Magnet>> {
|
||||||
|
let results = magnets::table
|
||||||
|
.select(Magnet::as_select())
|
||||||
|
.load(&mut self.conn)
|
||||||
|
.wrap_err("Failed to load magnets from database")?;
|
||||||
|
|
||||||
|
Ok(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn store_magnets(&mut self, post: &PostInfo) -> Result<usize> {
|
||||||
|
let published_at = post.timestamp.naive_utc();
|
||||||
|
let links = post
|
||||||
|
.magnet_links
|
||||||
|
.iter()
|
||||||
|
.map(|m| NewMagnet {
|
||||||
|
title: post.title.as_str(),
|
||||||
|
submitter: post.submitter.as_str(),
|
||||||
|
subreddit: post.subreddit.as_str(),
|
||||||
|
link: m,
|
||||||
|
published_at: &published_at,
|
||||||
|
})
|
||||||
|
.collect::<Vec<NewMagnet>>();
|
||||||
|
|
||||||
|
diesel::insert_into(magnets::table)
|
||||||
|
.values(&links)
|
||||||
|
.execute(&mut self.conn)
|
||||||
|
.wrap_err("Failed to save new magnet")
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/main.rs
41
src/main.rs
|
|
@ -8,18 +8,23 @@ use figment::{
|
||||||
Figment,
|
Figment,
|
||||||
};
|
};
|
||||||
use figment_file_provider_adapter::FileAdapter;
|
use figment_file_provider_adapter::FileAdapter;
|
||||||
use log::debug;
|
use log::{debug, warn};
|
||||||
use multimap::MultiMap;
|
use multimap::MultiMap;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::fs::create_dir_all;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use crate::db::Database;
|
||||||
use crate::magnet::{extract_magnet_links, Magnet};
|
use crate::magnet::{extract_magnet_links, Magnet};
|
||||||
use reddit_client::RedditClient;
|
use reddit_client::RedditClient;
|
||||||
|
|
||||||
|
mod db;
|
||||||
mod magnet;
|
mod magnet;
|
||||||
|
mod models;
|
||||||
mod reddit_client;
|
mod reddit_client;
|
||||||
|
mod schema;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
struct SectionConfig {
|
struct SectionConfig {
|
||||||
|
|
@ -36,6 +41,7 @@ struct Config {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct PostInfo {
|
struct PostInfo {
|
||||||
title: String,
|
title: String,
|
||||||
|
submitter: String,
|
||||||
magnet_links: Vec<Magnet>,
|
magnet_links: Vec<Magnet>,
|
||||||
subreddit: String,
|
subreddit: String,
|
||||||
timestamp: DateTime<Utc>,
|
timestamp: DateTime<Utc>,
|
||||||
|
|
@ -47,6 +53,10 @@ struct Args {
|
||||||
/// Path to the configuration file
|
/// Path to the configuration file
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
config: Option<String>,
|
config: Option<String>,
|
||||||
|
|
||||||
|
/// Path to the database file
|
||||||
|
#[arg(short, long)]
|
||||||
|
db: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Filters posts based on a title filter pattern
|
/// Filters posts based on a title filter pattern
|
||||||
|
|
@ -100,6 +110,23 @@ async fn main() -> Result<()> {
|
||||||
|
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
|
// Initialize database
|
||||||
|
let db_path = match args.db {
|
||||||
|
Some(path) => PathBuf::from(path),
|
||||||
|
None => ProjectDirs::from("fr", "enoent", "reddit-magnet")
|
||||||
|
.map(|p| p.data_dir().join("reddit-magnet.db"))
|
||||||
|
.ok_or_else(|| eyre!("Could not determine data directory"))?,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create parent directory if it doesn't exist
|
||||||
|
if let Some(parent) = db_path.parent() {
|
||||||
|
create_dir_all(parent)
|
||||||
|
.wrap_err_with(|| format!("Failed to create directory: {:?}", parent))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut db = Database::new(&db_path)
|
||||||
|
.wrap_err_with(|| format!("Failed to initialize database at {:?}", db_path))?;
|
||||||
|
|
||||||
let mut conf_extractor = Figment::new();
|
let mut conf_extractor = Figment::new();
|
||||||
let config_file_path: Option<PathBuf> = match args.config {
|
let config_file_path: Option<PathBuf> = match args.config {
|
||||||
Some(path) => Some(Path::new(&path).to_path_buf()),
|
Some(path) => Some(Path::new(&path).to_path_buf()),
|
||||||
|
|
@ -166,12 +193,20 @@ async fn main() -> Result<()> {
|
||||||
|
|
||||||
let magnet_links = extract_magnet_links(body);
|
let magnet_links = extract_magnet_links(body);
|
||||||
if !magnet_links.is_empty() {
|
if !magnet_links.is_empty() {
|
||||||
filtered_posts.push(PostInfo {
|
let post_info = PostInfo {
|
||||||
title: title.to_string(),
|
title: title.to_string(),
|
||||||
|
submitter: username.clone(),
|
||||||
subreddit: subreddit.to_string(),
|
subreddit: subreddit.to_string(),
|
||||||
magnet_links,
|
magnet_links,
|
||||||
timestamp: post.created,
|
timestamp: post.created,
|
||||||
});
|
};
|
||||||
|
|
||||||
|
// Store the post info in the database
|
||||||
|
if let Err(e) = db.store_magnets(&post_info) {
|
||||||
|
warn!("Failed to store post info in database: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
filtered_posts.push(post_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
26
src/models.rs
Normal file
26
src/models.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
use crate::schema::magnets;
|
||||||
|
use chrono::NaiveDateTime;
|
||||||
|
use diesel::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Queryable, Selectable)]
|
||||||
|
#[diesel(table_name = magnets)]
|
||||||
|
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||||
|
pub struct Magnet {
|
||||||
|
pub id: Option<i32>,
|
||||||
|
pub title: String,
|
||||||
|
pub submitter: String,
|
||||||
|
pub subreddit: String,
|
||||||
|
pub link: String,
|
||||||
|
pub published_at: NaiveDateTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Insertable)]
|
||||||
|
#[diesel(table_name = magnets)]
|
||||||
|
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||||
|
pub struct NewMagnet<'a> {
|
||||||
|
pub title: &'a str,
|
||||||
|
pub submitter: &'a str,
|
||||||
|
pub subreddit: &'a str,
|
||||||
|
pub link: &'a str,
|
||||||
|
pub published_at: &'a NaiveDateTime,
|
||||||
|
}
|
||||||
12
src/schema.rs
Normal file
12
src/schema.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
// @generated automatically by Diesel CLI.
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
magnets (id) {
|
||||||
|
id -> Nullable<Integer>,
|
||||||
|
title -> Text,
|
||||||
|
submitter -> Text,
|
||||||
|
subreddit -> Text,
|
||||||
|
link -> Text,
|
||||||
|
published_at -> Timestamp,
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue