use scryfall for mtg searcher
This commit is contained in:
parent
c7235acdef
commit
60efb9f527
@ -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" }
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user