Update stc library to Rust 2021 edition and update dependencies. Switch from home grown scryfall library to third party one.

This commit is contained in:
Adrian Kuschelyagi Malacoda 2023-03-12 19:40:15 -05:00
parent b9f3c8f445
commit 3286125d34
8 changed files with 48 additions and 102 deletions

View File

@ -2,15 +2,17 @@
name="stc" name="stc"
version="0.0.2" version="0.0.2"
authors=["Adrian Malacoda <adrian.malacoda@monarch-pass.net>"] authors=["Adrian Malacoda <adrian.malacoda@monarch-pass.net>"]
edition="2021"
[dependencies] [dependencies]
log = "0.4.1" log = "0.4.1"
env_logger = "0.5.10" env_logger = "0.5.10"
sqlite = "0.23.4" sqlite = "0.23.4"
select = "0.4.2" select = "0.4.2"
reqwest = "0.8.5" reqwest = { version = "0.11.14", features = ["blocking"] }
serde_json = "1.0.17" serde_json = "1.0.17"
retry = { git = "https://github.com/jimmycuadra/retry", rev = "3fa812e650d64ede61ea243fb83ef1a222ff0f84" } retry = { git = "https://github.com/jimmycuadra/retry", rev = "3fa812e650d64ede61ea243fb83ef1a222ff0f84" }
mopa = "0.2.2" mopa = "0.2.2"
linked-hash-map = "0.5.1" linked-hash-map = "0.5.1"
scryfall = { git = "http://gitlab.monarch-pass.net/malacoda/scryfall.git" } #scryfall = { git = "https://forge.ds8.zone/beyond/scryfall.git" }
scryfall = { git = "https://github.com/adrianmalacoda/scryfall-rs", rev = "e95579e7d9ee1ea7147b72f739f448a7e6dca85a" } # "0.11.1" # for sync api

0
README.md Normal file → Executable file
View File

6
src/lib.rs Normal file → Executable file
View File

@ -16,12 +16,12 @@ use mopa::Any;
pub trait Link: Any { pub trait Link: Any {
fn label (&self) -> &str; fn label (&self) -> &str;
fn url (&self) -> &str; fn url (&self) -> &str;
fn as_any(&self) -> &Any; fn as_any(&self) -> &dyn Any;
} }
mopafy!(Link); mopafy!(Link);
impl Link for Box<Link + 'static> { impl Link for Box<dyn Link + 'static> {
fn label (&self) -> &str { fn label (&self) -> &str {
(**self).label() (**self).label()
} }
@ -30,7 +30,7 @@ impl Link for Box<Link + 'static> {
(**self).url() (**self).url()
} }
fn as_any (&self) -> &Any { fn as_any (&self) -> &dyn Any {
self self
} }
} }

4
src/main.rs Normal file → Executable file
View File

@ -2,7 +2,6 @@ extern crate stc;
use std::env; use std::env;
#[macro_use]
extern crate log; extern crate log;
extern crate env_logger; extern crate env_logger;
@ -24,12 +23,11 @@ fn main () {
match searchers.exact_search(&term) { match searchers.exact_search(&term) {
Some(item) => { Some(item) => {
println!("{}: {}", item.label(), item.url());
if let Some(card) = item.downcast_ref::<MtgCard>() { if let Some(card) = item.downcast_ref::<MtgCard>() {
println!("{:?}", card); println!("{:?}", card);
} else if let Some(card) = item.downcast_ref::<YugiohCard>() { } else if let Some(card) = item.downcast_ref::<YugiohCard>() {
println!("{:?}", card); println!("{:?}", card);
} else {
println!("{}: {}", item.label(), item.url());
} }
}, },
None => println!("not found...") None => println!("not found...")

22
src/searchers/mediawiki.rs Normal file → Executable file
View File

@ -1,5 +1,5 @@
use Link; use crate::Link;
use searchers::Searcher; use crate::searchers::Searcher;
use reqwest; use reqwest;
use reqwest::StatusCode; use reqwest::StatusCode;
@ -7,14 +7,11 @@ use reqwest::StatusCode;
use select::document::Document; use select::document::Document;
use select::predicate::Name; use select::predicate::Name;
use retry;
use retry::retry; use retry::retry;
use retry::delay::Fixed; use retry::delay::Fixed;
use std; use std;
use std::io::Read;
//use std::any::Any;
use mopa::Any; use mopa::Any;
const NUM_RETRIES: usize = 10; const NUM_RETRIES: usize = 10;
@ -35,7 +32,7 @@ impl Link for WikiPage {
&self.url &self.url
} }
fn as_any (&self) -> &Any { fn as_any (&self) -> &dyn Any {
self self
} }
} }
@ -52,16 +49,17 @@ impl MediawikiSearcher {
} }
fn do_search (&self, name: &str) -> Result<String, Error> { fn do_search (&self, name: &str) -> Result<String, Error> {
let mut contents = String::new();
let api_url = &format!("{}{}", self.baseurl, name); let api_url = &format!("{}{}", self.baseurl, name);
let mut response = retry(Fixed::from_millis(RETRY_WAIT_MILLIS).take(NUM_RETRIES), || { let response = retry(Fixed::from_millis(RETRY_WAIT_MILLIS).take(NUM_RETRIES), || {
reqwest::get(api_url) reqwest::blocking::get(api_url)
})?; })?;
match response.status() { match response.status() {
StatusCode::Ok => { StatusCode::OK => {
response.read_to_string(&mut contents)?; match response.text() {
Result::Ok(contents) Ok(text) => Ok(text),
Err(error) => Result::Err(Error::Http(error))
}
}, },
_ => { _ => {
Result::Err(Error::Other(String::from("Not Found"))) Result::Err(Error::Other(String::from("Not Found")))

14
src/searchers/mod.rs Normal file → Executable file
View File

@ -2,7 +2,7 @@ pub mod mtg;
pub mod yugioh; pub mod yugioh;
pub mod mediawiki; pub mod mediawiki;
use Link; use crate::Link;
use linked_hash_map::LinkedHashMap; use linked_hash_map::LinkedHashMap;
pub trait Searcher<T: Link> { pub trait Searcher<T: Link> {
@ -13,7 +13,7 @@ pub trait Searcher<T: Link> {
fn exact_search (&self, name: &str) -> Option<T>; fn exact_search (&self, name: &str) -> Option<T>;
} }
type SearchFn = Box<Fn(String, bool) -> Option<Box<Link>>>; type SearchFn = Box<dyn Fn(String, bool) -> Option<Box<dyn Link>>>;
pub struct AggregateSearcher { pub struct AggregateSearcher {
searchers: LinkedHashMap<String, SearchFn> searchers: LinkedHashMap<String, SearchFn>
} }
@ -25,19 +25,19 @@ impl AggregateSearcher {
} }
} }
pub fn add_searcher<T: Link + 'static> (&mut self, prefix: &str, searcher: Box<Searcher<T>>) { pub fn add_searcher<T: Link + 'static> (&mut self, prefix: &str, searcher: Box<dyn Searcher<T>>) {
let searcher_closure = move |name: String, fuzzy: bool| { let searcher_closure = move |name: String, fuzzy: bool| {
(if fuzzy { (if fuzzy {
searcher.fuzzy_search(&name[..]) searcher.fuzzy_search(&name[..])
} else { } else {
searcher.exact_search(&name[..]) searcher.exact_search(&name[..])
}).map(|value| Box::new(value) as Box<Link>) }).map(|value| Box::new(value) as Box<dyn Link>)
}; };
self.searchers.insert(String::from(prefix), Box::new(searcher_closure)); self.searchers.insert(String::from(prefix), Box::new(searcher_closure));
} }
fn run_all_searchers (&self, name: &str) -> Option<Box<Link>> { fn run_all_searchers (&self, name: &str) -> Option<Box<dyn Link>> {
for (_, searcher) in &self.searchers { for (_, searcher) in &self.searchers {
let possible_value = searcher(String::from(name), false); let possible_value = searcher(String::from(name), false);
if possible_value.is_some() { if possible_value.is_some() {
@ -49,8 +49,8 @@ impl AggregateSearcher {
} }
} }
impl Searcher<Box<Link>> for AggregateSearcher { impl Searcher<Box<dyn Link>> for AggregateSearcher {
fn exact_search (&self, full_name: &str) -> Option<Box<Link>> { fn exact_search (&self, full_name: &str) -> Option<Box<dyn Link>> {
match split_prefix(full_name, ":") { match split_prefix(full_name, ":") {
Some((prefix, name)) => { Some((prefix, name)) => {
self.searchers.get(prefix).and_then(|searcher| searcher(String::from(name), true)) self.searchers.get(prefix).and_then(|searcher| searcher(String::from(name), true))

73
src/searchers/mtg.rs Normal file → Executable file
View File

@ -1,19 +1,16 @@
use Link; use crate::Link;
use searchers::Searcher; use crate::searchers::Searcher;
use scryfall; use scryfall;
use scryfall::{Scryfall, Card}; use scryfall::Card;
use retry; //use retry::retry;
use retry::retry; //use retry::delay::Fixed;
use retry::delay::Fixed;
use std;
use mopa::Any; use mopa::Any;
const NUM_RETRIES: usize = 10; // const NUM_RETRIES: usize = 10;
const RETRY_WAIT_MILLIS: u64 = 500; // const RETRY_WAIT_MILLIS: u64 = 500;
pub type MtgCard = Card; pub type MtgCard = Card;
@ -23,70 +20,24 @@ impl Link for Card {
} }
fn url (&self) -> &str { fn url (&self) -> &str {
&self.uri self.scryfall_uri.as_str()
} }
fn as_any (&self) -> &Any { fn as_any (&self) -> &dyn Any {
self self
} }
} }
pub struct MtgSearcher { pub struct MtgSearcher {}
scryfall: Scryfall
}
impl MtgSearcher { impl MtgSearcher {
pub fn new () -> MtgSearcher{ pub fn new () -> MtgSearcher{
MtgSearcher { MtgSearcher {}
scryfall: Scryfall::new()
}
}
fn do_search (&self, query: &str) -> Result<Option<Card>, Error> {
let mut result = retry(Fixed::from_millis(RETRY_WAIT_MILLIS).take(NUM_RETRIES), || {
self.scryfall.search(query, None, 0)
})?;
Ok(if !result.data.is_empty() {
Some(result.data.remove(0))
} else {
None
})
} }
} }
impl Searcher<Card> for MtgSearcher { impl Searcher<Card> for MtgSearcher {
fn exact_search (&self, name: &str) -> Option<Card> { fn exact_search (&self, name: &str) -> Option<Card> {
let search = format!(r#"!"{}""#, name); Card::named(name).ok()
self.do_search(&search).unwrap_or(None)
}
}
#[derive(Debug)]
enum Error {
Client(scryfall::Error),
Io(std::io::Error),
}
impl From<scryfall::Error> for Error {
fn from (error: scryfall::Error) -> Error {
Error::Client(error)
}
}
impl From<std::io::Error> for Error {
fn from (error: std::io::Error) -> Error {
Error::Io(error)
}
}
impl From<retry::Error<scryfall::Error>> for Error {
fn from (err: retry::Error<scryfall::Error>) -> Error {
match err {
retry::Error::Operation { error, total_delay, tries } => {
Error::Client(error)
}
}
} }
} }

23
src/searchers/yugioh.rs Normal file → Executable file
View File

@ -1,19 +1,14 @@
use Link; use crate::Link;
use searchers::Searcher; use crate::searchers::Searcher;
use reqwest; use reqwest;
use serde_json; use serde_json;
use serde_json::Value; use serde_json::Value;
use retry;
use retry::retry; use retry::retry;
use retry::delay::Fixed; use retry::delay::Fixed;
use std;
use std::io::Read;
//use std::any::Any;
use mopa::Any; use mopa::Any;
const NUM_RETRIES: usize = 10; const NUM_RETRIES: usize = 10;
@ -42,7 +37,7 @@ impl Link for YugiohCard {
&self.url &self.url
} }
fn as_any (&self) -> &Any { fn as_any (&self) -> &dyn Any {
self self
} }
} }
@ -55,13 +50,15 @@ impl YugiohSearcher {
} }
fn do_search (&self, name: &str) -> Result<String, Error> { fn do_search (&self, name: &str) -> Result<String, Error> {
let mut contents = String::new();
let api_url = &format!("http://yugiohprices.com/api/card_data/{}", name); let api_url = &format!("http://yugiohprices.com/api/card_data/{}", name);
let mut response = retry(Fixed::from_millis(RETRY_WAIT_MILLIS).take(NUM_RETRIES), || { let response = retry(Fixed::from_millis(RETRY_WAIT_MILLIS).take(NUM_RETRIES), || {
reqwest::get(api_url) reqwest::blocking::get(api_url)
})?; })?;
response.read_to_string(&mut contents)?;
Result::Ok(contents) match response.text() {
Ok(text) => Ok(text),
Err(error) => Result::Err(Error::Http(error))
}
} }
} }