Added some basic logging.
Fix cache invalidation (1 day for now).
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
use std::fs;
|
||||
use std::io;
|
||||
|
||||
use chrono::prelude::*;
|
||||
use chrono::Duration;
|
||||
use directories::ProjectDirs;
|
||||
use log::debug;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Cache {
|
||||
timestamp: u64,
|
||||
timestamp: DateTime<Utc>,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
@@ -25,14 +28,37 @@ impl Context {
|
||||
let cache = self.dirs.cache_dir().join(format!("{}-{}.bin", bin, key));
|
||||
|
||||
if cache.exists() {
|
||||
debug!("cache: bin={} key={} path={:?} exists", bin, key, cache);
|
||||
|
||||
fs::File::open(cache)
|
||||
.and_then(|file| {
|
||||
bincode::deserialize_from(&file).map_err(|_| {
|
||||
debug!("cache: bin={} key={} faild to deserialize", bin, key);
|
||||
|
||||
io::Error::new(io::ErrorKind::Other, "failed to deserialize cache entry")
|
||||
})
|
||||
})
|
||||
.and_then(|cache: Cache| {
|
||||
if cache.timestamp > Utc::now() {
|
||||
debug!("cache: bin={} key={} ok", bin, key);
|
||||
|
||||
Ok(cache)
|
||||
} else {
|
||||
debug!(
|
||||
"cache: bin={} key={} outdated ({})",
|
||||
bin, key, cache.timestamp
|
||||
);
|
||||
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"failed to deserialize cache entry",
|
||||
))
|
||||
}
|
||||
})
|
||||
.ok()
|
||||
} else {
|
||||
debug!("cache: bin={} key={} don't exists", bin, key);
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -42,7 +68,7 @@ impl Context {
|
||||
D: AsRef<[u8]>,
|
||||
{
|
||||
let entry = Cache {
|
||||
timestamp: 0,
|
||||
timestamp: Utc::now() + Duration::days(1),
|
||||
data: data.as_ref().to_vec(),
|
||||
};
|
||||
|
||||
@@ -54,6 +80,11 @@ impl Context {
|
||||
|
||||
let cache = cache.join(format!("{}-{}.bin", bin, key));
|
||||
|
||||
debug!(
|
||||
"cache: save: bin={} key={} path={:?} timestamp={}",
|
||||
bin, key, cache, entry.timestamp
|
||||
);
|
||||
|
||||
fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
|
||||
44
src/main.rs
44
src/main.rs
@@ -1,3 +1,5 @@
|
||||
use std::process::Command;
|
||||
|
||||
use structopt::StructOpt;
|
||||
|
||||
mod context;
|
||||
@@ -9,12 +11,35 @@ use crate::probe::*;
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt(name = "whoareyou", about = "Search for swedish phone numbers.")]
|
||||
struct Opt {
|
||||
#[structopt(short = "o", long = "open")]
|
||||
open: bool,
|
||||
|
||||
number: String,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let opt = Opt::from_args();
|
||||
|
||||
fern::Dispatch::new()
|
||||
.format(|out, message, record| {
|
||||
out.finish(format_args!(
|
||||
"{}[{}][{}] {}",
|
||||
chrono::Local::now().format("[%Y-%m-%d %H:%M:%S]"),
|
||||
record.target(),
|
||||
record.level(),
|
||||
message
|
||||
))
|
||||
})
|
||||
.level(log::LevelFilter::Off)
|
||||
.level_for("reqwest", log::LevelFilter::Off)
|
||||
.level_for("hyper", log::LevelFilter::Off)
|
||||
.level_for("tokio_reactor", log::LevelFilter::Off)
|
||||
.level_for("html5ever", log::LevelFilter::Off)
|
||||
.level_for("selectors", log::LevelFilter::Off)
|
||||
.chain(std::io::stdout())
|
||||
.apply()
|
||||
.expect("failed to init fern");
|
||||
|
||||
let mut probes: Vec<Box<Probe>> = vec![
|
||||
Box::new(Eniro),
|
||||
Box::new(Hitta),
|
||||
@@ -23,11 +48,22 @@ fn main() {
|
||||
Box::new(VemRingde),
|
||||
];
|
||||
|
||||
let mut ctx = Context::new();
|
||||
if opt.open {
|
||||
for probe in &mut probes {
|
||||
let uri = probe.uri(&opt.number);
|
||||
|
||||
for probe in &mut probes {
|
||||
if probe.search(&mut ctx, &opt.number).is_ok() {
|
||||
println!();
|
||||
Command::new("open")
|
||||
.arg(uri)
|
||||
.output()
|
||||
.expect("failed to execute process");
|
||||
}
|
||||
} else {
|
||||
let mut ctx = Context::new();
|
||||
|
||||
for probe in &mut probes {
|
||||
if probe.search(&mut ctx, &opt.number).is_ok() {
|
||||
println!();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,5 +13,6 @@ pub use self::vem_ringde::VemRingde;
|
||||
use crate::context::Context;
|
||||
|
||||
pub trait Probe {
|
||||
fn uri(&self, _: &str) -> String;
|
||||
fn search(&mut self, _: &mut Context, _: &str) -> Result<(), ()>;
|
||||
}
|
||||
|
||||
@@ -5,32 +5,34 @@ use crate::context::Context;
|
||||
use crate::probe::Probe;
|
||||
|
||||
#[derive(Debug, FromHtml)]
|
||||
#[html(selector = ".error-box")]
|
||||
#[html(selector = ".PhoneNoHit")]
|
||||
struct Error {
|
||||
#[html(selector = "h2", attr = "inner")]
|
||||
#[html(selector = ".search-info-container > p", attr = "inner")]
|
||||
message: String,
|
||||
}
|
||||
|
||||
// https://gulasidorna.eniro.se/hitta:{}
|
||||
pub struct Eniro;
|
||||
|
||||
impl Probe for Eniro {
|
||||
fn uri(&self, number: &str) -> String {
|
||||
format!("https://gulasidorna.eniro.se/hitta:{}", number)
|
||||
}
|
||||
|
||||
fn search(&mut self, ctx: &mut Context, number: &str) -> Result<(), ()> {
|
||||
let body = if let Some(cache) = ctx.cache_get("eniro", &number) {
|
||||
String::from_utf8(cache.data).unwrap()
|
||||
} else {
|
||||
reqwest::get(&format!("https://gulasidorna.eniro.se/hitta:{}", number))
|
||||
.unwrap()
|
||||
.text()
|
||||
.unwrap()
|
||||
};
|
||||
let body = reqwest::get(&self.uri(number)).unwrap().text().unwrap();
|
||||
|
||||
ctx.cache_set("eniro", &number, body.as_bytes())
|
||||
.expect("wut?! why not?!");
|
||||
ctx.cache_set("eniro", &number, body.as_bytes())
|
||||
.expect("wut?! why not?!");
|
||||
|
||||
body
|
||||
};
|
||||
|
||||
if let Ok(error) = Error::from_html(&body) {
|
||||
println!("eniro.se:");
|
||||
println!(" {}", error.message);
|
||||
println!(" Antal sökningar på det här numret: {}", error.message);
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
|
||||
@@ -39,22 +39,24 @@ struct Comment {
|
||||
timestamp: u64,
|
||||
}
|
||||
|
||||
// https://www.hitta.se/vem-ringde/{}
|
||||
pub struct Hitta;
|
||||
|
||||
impl Probe for Hitta {
|
||||
fn uri(&self, number: &str) -> String {
|
||||
format!("https://www.hitta.se/vem-ringde/{}", number)
|
||||
}
|
||||
|
||||
fn search(&mut self, ctx: &mut Context, number: &str) -> Result<(), ()> {
|
||||
let body = if let Some(cache) = ctx.cache_get("hitta", &number) {
|
||||
String::from_utf8(cache.data).unwrap()
|
||||
} else {
|
||||
reqwest::get(&format!("https://www.hitta.se/vem-ringde/{}", number))
|
||||
.unwrap()
|
||||
.text()
|
||||
.unwrap()
|
||||
};
|
||||
let body = reqwest::get(&self.uri(number)).unwrap().text().unwrap();
|
||||
|
||||
ctx.cache_set("hitta", &number, body.as_bytes())
|
||||
.expect("wut?! why not?!");
|
||||
ctx.cache_set("hitta", &number, body.as_bytes())
|
||||
.expect("wut?! why not?!");
|
||||
|
||||
body
|
||||
};
|
||||
|
||||
let re = Regex::new(r#"<script>__NEXT_DATA__ = (.*?);__NEXT_LOADED_PAGES__"#).unwrap();
|
||||
|
||||
|
||||
@@ -11,25 +11,24 @@ struct Info {
|
||||
message: String,
|
||||
}
|
||||
|
||||
// http://konsumentinfo.se/telefonnummer/sverige/{}
|
||||
pub struct KonsumentInfo;
|
||||
|
||||
impl Probe for KonsumentInfo {
|
||||
fn uri(&self, number: &str) -> String {
|
||||
format!("http://konsumentinfo.se/telefonnummer/sverige/{}", number)
|
||||
}
|
||||
|
||||
fn search(&mut self, ctx: &mut Context, number: &str) -> Result<(), ()> {
|
||||
let body = if let Some(cache) = ctx.cache_get("konsument_info", &number) {
|
||||
String::from_utf8(cache.data).unwrap()
|
||||
} else {
|
||||
reqwest::get(&format!(
|
||||
"http://konsumentinfo.se/telefonnummer/sverige/{}",
|
||||
number
|
||||
))
|
||||
.unwrap()
|
||||
.text()
|
||||
.unwrap()
|
||||
};
|
||||
let body = reqwest::get(&self.uri(number)).unwrap().text().unwrap();
|
||||
|
||||
ctx.cache_set("konsument_info", &number, body.as_bytes())
|
||||
.expect("wut?! why not?!");
|
||||
ctx.cache_set("konsument_info", &number, body.as_bytes())
|
||||
.expect("wut?! why not?!");
|
||||
|
||||
body
|
||||
};
|
||||
|
||||
println!("konsumentinfo.se:");
|
||||
|
||||
|
||||
@@ -11,25 +11,24 @@ struct Info {
|
||||
message: String,
|
||||
}
|
||||
|
||||
// http://www.telefonforsaljare.nu/telefonnummer/{}/
|
||||
pub struct Telefonforsaljare;
|
||||
|
||||
impl Probe for Telefonforsaljare {
|
||||
fn uri(&self, number: &str) -> String {
|
||||
format!("http://www.telefonforsaljare.nu/telefonnummer/{}/", number)
|
||||
}
|
||||
|
||||
fn search(&mut self, ctx: &mut Context, number: &str) -> Result<(), ()> {
|
||||
let body = if let Some(cache) = ctx.cache_get("telefonforsaljare", &number) {
|
||||
String::from_utf8(cache.data).unwrap()
|
||||
} else {
|
||||
reqwest::get(&format!(
|
||||
"http://www.telefonforsaljare.nu/telefonnummer/{}/",
|
||||
number
|
||||
))
|
||||
.unwrap()
|
||||
.text()
|
||||
.unwrap()
|
||||
};
|
||||
let body = reqwest::get(&self.uri(number)).unwrap().text().unwrap();
|
||||
|
||||
ctx.cache_set("telefonforsaljare", &number, body.as_bytes())
|
||||
.expect("wut?! why not?!");
|
||||
ctx.cache_set("telefonforsaljare", &number, body.as_bytes())
|
||||
.expect("wut?! why not?!");
|
||||
|
||||
body
|
||||
};
|
||||
|
||||
println!("telefonforsaljare.nu:");
|
||||
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
use crate::context::Context;
|
||||
use crate::probe::Probe;
|
||||
|
||||
// http://vemringde.se/?q={}
|
||||
pub struct VemRingde;
|
||||
|
||||
impl Probe for VemRingde {
|
||||
fn uri(&self, number: &str) -> String {
|
||||
format!("http://vemringde.se/?q={}", number)
|
||||
}
|
||||
|
||||
fn search(&mut self, ctx: &mut Context, number: &str) -> Result<(), ()> {
|
||||
let body = if let Some(cache) = ctx.cache_get("vem_ringde", &number) {
|
||||
let _body = if let Some(cache) = ctx.cache_get("vem_ringde", &number) {
|
||||
String::from_utf8(cache.data).unwrap()
|
||||
} else {
|
||||
reqwest::get(&format!("http://vemringde.se/?q={}", number))
|
||||
.unwrap()
|
||||
.text()
|
||||
.unwrap()
|
||||
};
|
||||
let body = reqwest::get(&self.uri(number)).unwrap().text().unwrap();
|
||||
|
||||
ctx.cache_set("vem_ringde", &number, body.as_bytes())
|
||||
.expect("wut?! why not?!");
|
||||
ctx.cache_set("vem_ringde", &number, body.as_bytes())
|
||||
.expect("wut?! why not?!");
|
||||
|
||||
body
|
||||
};
|
||||
|
||||
Err(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user