You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

89 lines
2.1KB

  1. extern crate reqwest;
  2. #[macro_use]
  3. extern crate lazy_static;
  4. use std::collections::HashMap;
  5. use std::error::Error;
  6. use std::sync::{Arc, RwLock};
  7. use reqwest::StatusCode;
  8. #[derive(Clone, Debug, PartialEq)]
  9. pub struct LinkResult {
  10. pub code: Option<StatusCode>,
  11. /// Whether the HTTP request didn't make it to getting a HTTP code
  12. pub error: Option<String>,
  13. }
  14. impl LinkResult {
  15. pub fn is_valid(&self) -> bool {
  16. if self.error.is_some() {
  17. return false;
  18. }
  19. if let Some(c) = self.code {
  20. return c.is_success();
  21. }
  22. true
  23. }
  24. pub fn message(&self) -> String {
  25. if let Some(ref e) = self.error {
  26. return e.clone();
  27. }
  28. if let Some(c) = self.code {
  29. return format!("{}", c);
  30. }
  31. "Unknown error".to_string()
  32. }
  33. }
  34. lazy_static! {
  35. // Keep history of link checks so a rebuild doesn't have to check again
  36. static ref LINKS: Arc<RwLock<HashMap<String, LinkResult>>> = Arc::new(RwLock::new(HashMap::new()));
  37. }
  38. pub fn check_url(url: &str) -> LinkResult {
  39. {
  40. let guard = LINKS.read().unwrap();
  41. if let Some(res) = guard.get(url) {
  42. return res.clone();
  43. }
  44. }
  45. // Need to actually do the link checking
  46. let res = match reqwest::get(url) {
  47. Ok(response) => LinkResult { code: Some(response.status()), error: None },
  48. Err(e) => LinkResult { code: None, error: Some(e.description().to_string()) },
  49. };
  50. LINKS.write().unwrap().insert(url.to_string(), res.clone());
  51. return res;
  52. }
  53. #[cfg(test)]
  54. mod tests {
  55. use super::{LINKS, check_url};
  56. #[test]
  57. fn can_validate_ok_links() {
  58. let url = "https://google.com";
  59. let res = check_url(url);
  60. assert!(res.is_valid());
  61. assert!(LINKS.read().unwrap().get(url).is_some());
  62. let res = check_url(url);
  63. assert!(res.is_valid());
  64. }
  65. #[test]
  66. fn can_fail_404_links() {
  67. let res = check_url("https://google.comys");
  68. assert_eq!(res.is_valid(), false);
  69. assert!(res.code.is_none());
  70. assert!(res.error.is_some());
  71. }
  72. }