use scryfall for mtg searcher

This commit is contained in:
Adrian Malacoda 2018-05-06 03:20:02 -05:00
parent c7235acdef
commit 60efb9f527
3 changed files with 28 additions and 73 deletions

View File

@ -13,3 +13,4 @@ serde_json = "1.0.17"
retry = { git = "https://github.com/jimmycuadra/retry", rev = "3fa812e650d64ede61ea243fb83ef1a222ff0f84" }
mopa = "0.2.2"
linked-hash-map = "0.5.1"
scryfall = { git = "http://gitlab.monarch-pass.net/malacoda/scryfall.git" }

View File

@ -3,6 +3,7 @@ extern crate select;
extern crate serde_json;
extern crate retry;
extern crate linked_hash_map;
extern crate scryfall;
#[macro_use]
extern crate mopa;

View File

@ -1,45 +1,27 @@
use Link;
use searchers::Searcher;
use hyper;
use hyper::Client;
use serde_json;
use serde_json::Value;
use scryfall;
use scryfall::{Scryfall, Card};
use retry;
use retry::retry;
use retry::delay::Fixed;
use std;
use std::io::Read;
//use std::any::Any;
use mopa::Any;
const NUM_RETRIES: usize = 10;
const RETRY_WAIT_MILLIS: u64 = 500;
#[derive(Debug)]
pub struct MtgCard {
pub name: String,
pub cost: Option<String>,
pub typeline: String,
pub rules: Option<String>,
pub flavor: Option<String>,
pub power: Option<String>,
pub toughness: Option<String>,
pub url: String,
pub image_url: String
}
impl Link for MtgCard {
impl Link for Card {
fn label (&self) -> &str {
&self.name
}
fn url (&self) -> &str {
&self.url
&self.uri
}
fn as_any (&self) -> &Any {
@ -48,69 +30,45 @@ impl Link for MtgCard {
}
pub struct MtgSearcher {
client: Client
scryfall: Scryfall
}
impl MtgSearcher {
pub fn new () -> MtgSearcher {
MtgSearcher {
client: Client::new()
scryfall: Scryfall::new()
}
}
fn do_search (&self, name: &str) -> Result<String, Error> {
let mut contents = String::new();
let api_url = &format!("https://api.magicthegathering.io/v1/cards?name={}", name);
let mut response = retry(Fixed::from_millis(RETRY_WAIT_MILLIS).take(NUM_RETRIES), || {
self.client.get(api_url).send()
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)
})?;
response.read_to_string(&mut contents)?;
Result::Ok(contents)
Ok(if !result.data.is_empty() {
Some(result.data.remove(0))
} else {
None
})
}
}
fn parse_entry (page: String) -> Result<MtgCard, Error> {
let parsed: Value = serde_json::from_str(&page)?;
for entry in parsed["cards"].as_array().unwrap_or(&vec![]) {
if entry["imageUrl"].as_str().is_some() {
let card_name = entry["name"].as_str().map(String::from).expect("expected name in json data");
let card_url = format!("http://magiccards.info/query?q=!{}", card_name.replace(" ", "+"));
return Result::Ok(MtgCard {
name: card_name,
cost: entry["manaCost"].as_str().map(String::from),
typeline: entry["type"].as_str().map(String::from).expect("expected type in json data"),
rules: entry["text"].as_str().map(String::from),
flavor: entry["flavor"].as_str().map(String::from),
power: entry["power"].as_str().map(String::from),
toughness: entry["toughness"].as_str().map(String::from),
url: card_url,
image_url: entry["imageUrl"].as_str().map(String::from).expect("expected image url in json data")
});
}
}
Result::Err(Error::Other(String::from("No card info found")))
}
impl Searcher<MtgCard> for MtgSearcher {
fn exact_search (&self, name: &str) -> Option<MtgCard> {
let search = format!(r#""{}""#, name);
self.do_search(&search).and_then(parse_entry).ok()
impl Searcher<Card> for MtgSearcher {
fn exact_search (&self, name: &str) -> Option<Card> {
let search = format!(r#"!{}"#, name);
self.do_search(&search).unwrap_or(None)
}
}
#[derive(Debug)]
enum Error {
Http(hyper::error::Error),
Client(scryfall::Error),
Io(std::io::Error),
Json(serde_json::Error),
Other(String)
}
impl From<hyper::error::Error> for Error {
fn from (error: hyper::error::Error) -> Error {
Error::Http(error)
impl From<scryfall::Error> for Error {
fn from (error: scryfall::Error) -> Error {
Error::Client(error)
}
}
@ -120,17 +78,12 @@ impl From<std::io::Error> for Error {
}
}
impl From<serde_json::Error> for Error {
fn from (error: serde_json::Error) -> Error {
Error::Json(error)
}
}
impl From<retry::Error<hyper::Error>> for Error {
fn from (err: retry::Error<hyper::Error>) -> 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::Http(error)
Error::Client(error)
}
}
}