logging and retries implemented

This commit is contained in:
Alie 2023-07-14 19:04:58 +02:00
parent 985cea9894
commit 6d61144a0d
5 changed files with 416 additions and 105 deletions

323
Cargo.lock generated
View File

@ -11,6 +11,21 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "async-stream" name = "async-stream"
version = "0.3.4" version = "0.3.4"
@ -33,6 +48,17 @@ dependencies = [
"syn 1.0.107", "syn 1.0.107",
] ]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi 0.1.19",
"libc",
"winapi",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
@ -112,6 +138,20 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"winapi",
]
[[package]] [[package]]
name = "core-foundation" name = "core-foundation"
version = "0.9.3" version = "0.9.3"
@ -128,16 +168,6 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]]
name = "ctor"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
dependencies = [
"quote",
"syn 1.0.107",
]
[[package]] [[package]]
name = "derive_deref" name = "derive_deref"
version = "1.1.1" version = "1.1.1"
@ -364,6 +394,15 @@ version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.2.6" version = "0.2.6"
@ -444,6 +483,29 @@ dependencies = [
"tokio-native-tls", "tokio-native-tls",
] ]
[[package]]
name = "iana-time-zone"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]] [[package]]
name = "idna" name = "idna"
version = "0.3.0" version = "0.3.0"
@ -528,11 +590,10 @@ checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.17" version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
dependencies = [ dependencies = [
"cfg-if",
"serde", "serde",
"value-bag", "value-bag",
] ]
@ -587,9 +648,11 @@ dependencies = [
name = "mastodon-image-uploader-bot" name = "mastodon-image-uploader-bot"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"log",
"mastodon-async", "mastodon-async",
"reqwest", "reqwest",
"serde", "serde",
"stderrlog",
"tokio", "tokio",
"tokio-test", "tokio-test",
"toml 0.7.6", "toml 0.7.6",
@ -647,13 +710,22 @@ dependencies = [
"tempfile", "tempfile",
] ]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "1.15.0" version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
dependencies = [ dependencies = [
"hermit-abi", "hermit-abi 0.2.6",
"libc", "libc",
] ]
@ -1041,12 +1113,84 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]] [[package]]
name = "sval" name = "stderrlog"
version = "1.0.0-alpha.5" version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45f6ee7c7b87caf59549e9fe45d6a69c75c8019e79e212a835c5da0e92f0ba08" checksum = "69a26bbf6de627d389164afa9783739b56746c6c72c4ed16539f4ff54170327b"
dependencies = [
"atty",
"chrono",
"log",
"termcolor",
"thread_local",
]
[[package]]
name = "sval"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b031320a434d3e9477ccf9b5756d57d4272937b8d22cb88af80b7633a1b78b1"
[[package]]
name = "sval_buffer"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bf7e9412af26b342f3f2cc5cc4122b0105e9d16eb76046cd14ed10106cf6028"
dependencies = [
"sval",
"sval_ref",
]
[[package]]
name = "sval_dynamic"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0ef628e8a77a46ed3338db8d1b08af77495123cc229453084e47cd716d403cf"
dependencies = [
"sval",
]
[[package]]
name = "sval_fmt"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dc09e9364c2045ab5fa38f7b04d077b3359d30c4c2b3ec4bae67a358bd64326"
dependencies = [
"itoa",
"ryu",
"sval",
]
[[package]]
name = "sval_json"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ada6f627e38cbb8860283649509d87bc4a5771141daa41c78fd31f2b9485888d"
dependencies = [
"itoa",
"ryu",
"sval",
]
[[package]]
name = "sval_ref"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "703ca1942a984bd0d9b5a4c0a65ab8b4b794038d080af4eb303c71bc6bf22d7c"
dependencies = [
"sval",
]
[[package]]
name = "sval_serde"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830926cd0581f7c3e5d51efae4d35c6b6fc4db583842652891ba2f1bed8db046"
dependencies = [ dependencies = [
"serde", "serde",
"sval",
"sval_buffer",
"sval_fmt",
] ]
[[package]] [[package]]
@ -1091,6 +1235,15 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.38" version = "1.0.38"
@ -1111,6 +1264,16 @@ dependencies = [
"syn 1.0.107", "syn 1.0.107",
] ]
[[package]]
name = "thread_local"
version = "1.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
dependencies = [
"cfg-if",
"once_cell",
]
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.19" version = "0.3.19"
@ -1357,16 +1520,38 @@ dependencies = [
[[package]] [[package]]
name = "value-bag" name = "value-bag"
version = "1.0.0-alpha.9" version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" checksum = "d92ccd67fb88503048c01b59152a04effd0782d035a83a6d256ce6085f08f4a3"
dependencies = [
"value-bag-serde1",
"value-bag-sval2",
]
[[package]]
name = "value-bag-serde1"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0b9f3feef403a50d4d67e9741a6d8fc688bcbb4e4f31bd4aab72cc690284394"
dependencies = [ dependencies = [
"ctor",
"erased-serde", "erased-serde",
"serde", "serde",
"serde_fmt", "serde_fmt",
]
[[package]]
name = "value-bag-sval2"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30b24f4146b6f3361e91cbf527d1fb35e9376c3c0cef72ca5ec5af6d640fad7d"
dependencies = [
"sval", "sval",
"version_check", "sval_buffer",
"sval_dynamic",
"sval_fmt",
"sval_json",
"sval_ref",
"sval_serde",
] ]
[[package]] [[package]]
@ -1528,19 +1713,28 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
dependencies = [
"windows-targets 0.48.1",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.42.0" version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm 0.42.1",
"windows_aarch64_msvc", "windows_aarch64_msvc 0.42.1",
"windows_i686_gnu", "windows_i686_gnu 0.42.1",
"windows_i686_msvc", "windows_i686_msvc 0.42.1",
"windows_x86_64_gnu", "windows_x86_64_gnu 0.42.1",
"windows_x86_64_gnullvm", "windows_x86_64_gnullvm 0.42.1",
"windows_x86_64_msvc", "windows_x86_64_msvc 0.42.1",
] ]
[[package]] [[package]]
@ -1549,7 +1743,7 @@ version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [ dependencies = [
"windows-targets", "windows-targets 0.42.1",
] ]
[[package]] [[package]]
@ -1558,13 +1752,28 @@ version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm 0.42.1",
"windows_aarch64_msvc", "windows_aarch64_msvc 0.42.1",
"windows_i686_gnu", "windows_i686_gnu 0.42.1",
"windows_i686_msvc", "windows_i686_msvc 0.42.1",
"windows_x86_64_gnu", "windows_x86_64_gnu 0.42.1",
"windows_x86_64_gnullvm", "windows_x86_64_gnullvm 0.42.1",
"windows_x86_64_msvc", "windows_x86_64_msvc 0.42.1",
]
[[package]]
name = "windows-targets"
version = "0.48.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
dependencies = [
"windows_aarch64_gnullvm 0.48.0",
"windows_aarch64_msvc 0.48.0",
"windows_i686_gnu 0.48.0",
"windows_i686_msvc 0.48.0",
"windows_x86_64_gnu 0.48.0",
"windows_x86_64_gnullvm 0.48.0",
"windows_x86_64_msvc 0.48.0",
] ]
[[package]] [[package]]
@ -1573,42 +1782,84 @@ version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.42.1" version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.42.1" version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.42.1" version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.42.1" version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.42.1" version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.42.1" version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.5.0" version = "0.5.0"

View File

@ -11,6 +11,8 @@ tokio-test = "0.4.2"
reqwest = "0.11.14" reqwest = "0.11.14"
serde = "1.0.171" serde = "1.0.171"
toml = "0.7.1" toml = "0.7.1"
log = "0.4.19"
stderrlog = "0.5.4"
[dependencies.mastodon-async] [dependencies.mastodon-async]
version = "1.0" version = "1.0"

View File

@ -6,7 +6,8 @@ bio = "Bot who posts images of sleeping girls every 6 hours."
[files] [files]
urls = "./urls.csv" urls = "./urls.csv"
posted = "./posted.csv" posted = "./posted.csv"
tempfile = "./.tmp" tempfile = ".tmp"
[errors] [errors]
out_of_images = "@Sugui@awoo.fai.st @MeDueleLaTeta@awoo.fai.st me quedé sin chicas" out_of_images = "@Sugui@awoo.fai.st @MeDueleLaTeta@awoo.fai.st me quedé sin chicas"
retry = 10

View File

@ -1,10 +0,0 @@
#!/bin/sh
mastodon-image-uploader-bot >./tmp/log.out 2>./tmp/log.err
if [ ! -s ./tmp/log.err ]; then
echo -n "$(date +"[%Y-%M-%d %T]") success: " >> ./bot.log
cat ./tmp/log.out >> ./bot.log
else
echo -n "$(date +"[%Y-%M-%d %T]") errors: " >> ./bot.log
cat ./tmp/log.err >> ./bot.log
fi

View File

@ -1,17 +1,21 @@
use mastodon_async::entities::visibility::Visibility; use mastodon_async::entities::visibility::Visibility;
use mastodon_async::helpers::toml as masto_toml; use mastodon_async::helpers::{cli, toml as masto_toml};
use mastodon_async::prelude::*; use mastodon_async::prelude::*;
use mastodon_async::{helpers::cli, Result}; use mastodon_async::Result as MastoResult;
use reqwest; use reqwest;
use serde::Deserialize; use serde::Deserialize;
use std::collections::HashSet; use std::collections::HashSet;
use std::io::Cursor; use std::error::Error;
use std::io::Write; use std::io::{Cursor, Write};
use std::process::Command; use std::process::{exit, Command};
use toml; use toml;
use log;
const CONFIG_FILENAME: &str = "config.toml"; const CONFIG_FILENAME: &str = "config.toml";
type DynResult<T> = Result<T, Box<dyn Error>>;
#[derive(Deserialize)] #[derive(Deserialize)]
struct Config { struct Config {
bot: Bot, bot: Bot,
@ -36,80 +40,144 @@ struct Files {
#[derive(Deserialize)] #[derive(Deserialize)]
struct Errors { struct Errors {
out_of_images: String, out_of_images: String,
} retry: u8,
/// Parses the given filename to a config struct
fn parse_config(filename: &str) -> Config {
let toml_file = std::fs::read_to_string(filename)
.expect("No config file, consider getting the original one and modifing it");
toml::from_str(&toml_file).expect("Malformed config file, check the original one for reference")
} }
#[tokio::main] // requires `features = ["mt"] #[tokio::main] // requires `features = ["mt"]
async fn main() -> Result<()> { async fn main() -> DynResult<()> {
let config: Config = parse_config(CONFIG_FILENAME); stderrlog::new()
.module(module_path!())
.quiet(false)
.verbosity(4) // Debug
.timestamp(stderrlog::Timestamp::Second)
.init()?;
let config: Config = match parse_config(CONFIG_FILENAME) {
Ok(config) => config,
Err(err) => {
log::error!("Config file parsing unsuccesful: {}", err);
exit(1);
}
};
let mastodon = if let Ok(data) = masto_toml::from_file("mastodon-data.toml") { let mastodon = if let Ok(data) = masto_toml::from_file("mastodon-data.toml") {
Mastodon::from(data) Mastodon::from(data)
} else { } else {
register(&config).await? match register(&config).await {
Ok(account) => account,
Err(err) => {
log::error!("Api registation unsuccesful: {}", err);
exit(1);
}
}
}; };
match get_next_url(&config) { match get_next_url(&config) {
Some(url) => { Ok(url) => match url {
post_image(&mastodon, &url, &config).await; Some(url) => {
update_bio(&mastodon, &config).await; let mut retry: u8 = 0;
while let Err(err) = post_image(&mastodon, &url, &config).await {
log::warn!("Cannot post image, retry: {}, {}", retry, err);
retry += 1;
if retry >= config.errors.retry {
log::error!("Max ammount of retries reached on post_image");
log::info!("Reverting file changes");
while let Err(err) = pop_last_line_of_file(&config.files.posted) {
log::warn!("Failed to revert, retrying: {}", err);
}
exit(1);
}
}
let mut retry: u8 = 0;
while let Err(err) = update_bio(&mastodon, &config).await {
log::warn!("Cannot update bio, retry: {}, {}", retry, err);
retry += 1;
if retry >= config.errors.retry {
log::error!("Max ammount of retries reached on update bio");
exit(1);
}
}
}
None => {
let mut retry: u8 = 0;
while let Err(err) = post(&mastodon, &config.errors.out_of_images).await {
log::warn!("Cannot post, retry: {}, {}", retry, err);
retry += 1;
if retry >= config.errors.retry {
log::error!("Max ammount of retries reached on post");
exit(1);
}
}
}
},
Err(err) => {
log::error!("Cannot get next image: {}", err);
match post(&mastodon, &err.to_string()).await {
Ok(_) => {}
Err(err) => {
log::error!("Cannot post error message: {}", err);
exit(1);
}
};
} }
None => post(&mastodon, &config.errors.out_of_images).await, }
};
Ok(()) Ok(())
} }
fn get_next_url(config: &Config) -> Option<String> { /// Parses the given filename to a config struct
let binding = std::fs::read_to_string(&config.files.posted).expect("Posted file not found"); fn parse_config(filename: &str) -> DynResult<Config> {
let toml_file = std::fs::read_to_string(filename)?; //.expect("No config file, consider getting the original one and modifing it");
Ok(toml::from_str(&toml_file)?) //("Malformed config file, check the original one for reference")
}
fn pop_last_line_of_file(filename: &str) -> DynResult<()> {
let binding = std::fs::read_to_string(filename)?;
let mut posted: Vec<_> = binding.lines().collect();
posted.pop();
std::fs::write(filename, posted.concat())?;
log::info!("Success reverting changes");
Ok(())
}
fn get_next_url(config: &Config) -> DynResult<Option<String>> {
let binding = std::fs::read_to_string(&config.files.posted)?; //.expect("Posted file not found");
let posted = binding.lines().collect::<HashSet<&str>>(); let posted = binding.lines().collect::<HashSet<&str>>();
let binding = std::fs::read_to_string(&config.files.urls).expect("Urls file not found"); let binding = std::fs::read_to_string(&config.files.urls)?; //.expect("Urls file not found");
let urls = binding.lines().collect::<HashSet<&str>>(); let urls = binding.lines().collect::<HashSet<&str>>();
let urls = urls.difference(&posted).collect::<Vec<_>>(); let urls = urls.difference(&posted).collect::<Vec<_>>();
if urls.is_empty() { if urls.is_empty() {
None Ok(None)
} else { } else {
let mut file = std::fs::OpenOptions::new() let mut file = std::fs::OpenOptions::new()
.write(true) .write(true)
.append(true) // This is needed to append to file .append(true) // This is needed to append to file
.open(&config.files.posted) .open(&config.files.posted)?; //.expect("Cannot open posted file"); // Maybe we should retry just in case
.expect("Cannot open posted file"); // Maybe we should retry just in case write!(file, "{}\n", urls[0])?; //.expect("Cannot write to posted file"); // maybe we should retry tbh
write!(file, "{}\n", urls[0]).expect("Cannot write to posted file"); // maybe we should retry tbh Ok(Some(urls[0].to_string().clone()))
Some(urls[0].to_string().clone())
} }
} }
async fn post_image(account: &Mastodon, url: &String, config: &Config) { async fn post_image(account: &Mastodon, url: &String, config: &Config) -> DynResult<()> {
fetch_url(url.to_string(), &config.files.tempfile) fetch_url(url.to_string(), &config.files.tempfile).await?; //.expect("Error fetching url");
.await
.expect("Error fetching url");
let attachment = account let attachment = account
.media(&config.files.tempfile, Some(url.to_string())) .media(&config.files.tempfile, Some(url.to_string()))
.await .await?; //.expect("Attachment upload error");
.expect("Attachment upload error");
let attachment = account let attachment = account
.wait_for_processing(attachment, Default::default()) .wait_for_processing(attachment, Default::default())
.await .await?; //.expect("Attachment processing error");
.expect("Attachment processing error");
let status = StatusBuilder::new() let status = StatusBuilder::new()
.media_ids(&[attachment.id]) .media_ids(&[attachment.id])
.visibility(Visibility::Unlisted) .visibility(Visibility::Unlisted)
.sensitive(true) .sensitive(true)
.build() .build()?; //.expect("Could not build status"); // we should retry
.expect("Could not build status"); // we should retry account.new_status(status).await?; //.expect("Error generating status"); // we should retry or delete last url in posted
account.new_status(status).await.expect("Error generating status"); // we should retry or delete last url in posted log::info!("Image status posted: {}", url);
println!("Status posted") Ok(())
} }
async fn update_bio(account: &Mastodon, config: &Config) { async fn update_bio(account: &Mastodon, config: &Config) -> DynResult<()> {
let binding = std::fs::read_to_string(&config.files.posted).expect("Posted file not found"); let binding = std::fs::read_to_string(&config.files.posted)?; //.expect("Posted file not found");
let posted = binding.lines().collect::<HashSet<&str>>(); let posted = binding.lines().collect::<HashSet<&str>>();
let binding = std::fs::read_to_string(&config.files.urls).expect("Url file not found"); let binding = std::fs::read_to_string(&config.files.urls)?; //.expect("Url file not found");
let urls = binding.lines().collect::<HashSet<&str>>(); let urls = binding.lines().collect::<HashSet<&str>>();
let remaining = urls.difference(&posted).count(); let remaining = urls.difference(&posted).count();
@ -126,31 +194,30 @@ async fn update_bio(account: &Mastodon, config: &Config) {
config.bot.bio, remaining config.bot.bio, remaining
), ),
]) ])
.spawn() .spawn()? //.expect("Could not spawn curl")
.expect("Could not spawn curl") .wait()?; //.expect("Curl failed");
.wait() Ok(())
.expect("Curl failed");
} }
async fn post(account: &Mastodon, msg: &str) { async fn post(account: &Mastodon, msg: &str) -> MastoResult<()> {
let status = StatusBuilder::new() let status = StatusBuilder::new()
.visibility(Visibility::Direct) .visibility(Visibility::Direct)
.status(msg) .status(msg)
.build() .build()?; //.expect("Error building error status");
.expect("Error building error status"); account.new_status(status).await?; //.expect("Error posting error status");
account.new_status(status).await.expect("Error posting error status"); log::info!("Text status posted: {}", msg);
println!("Error status posted") Ok(())
} }
async fn fetch_url(url: String, file_name: &String) -> Result<()> { async fn fetch_url(url: String, file_name: &String) -> MastoResult<()> {
let response = reqwest::get(url).await?; let response = reqwest::get(url);
let mut file = std::fs::File::create(file_name)?; let mut file = std::fs::File::create(file_name)?;
let mut content = Cursor::new(response.bytes().await?); let mut content = Cursor::new(response.await?.bytes().await?);
std::io::copy(&mut content, &mut file)?; std::io::copy(&mut content, &mut file)?;
Ok(()) Ok(())
} }
async fn register(config: &Config) -> Result<Mastodon> { async fn register(config: &Config) -> MastoResult<Mastodon> {
let registration = Registration::new(&config.bot.instance) let registration = Registration::new(&config.bot.instance)
.client_name(&config.bot.name) .client_name(&config.bot.name)
.scopes(Scopes::write_all()) .scopes(Scopes::write_all())