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" }
|
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" }
|
||||||
|
@ -3,6 +3,7 @@ extern crate select;
|
|||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate retry;
|
extern crate retry;
|
||||||
extern crate linked_hash_map;
|
extern crate linked_hash_map;
|
||||||
|
extern crate scryfall;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate mopa;
|
extern crate mopa;
|
||||||
|
@ -1,45 +1,27 @@
|
|||||||
use Link;
|
use Link;
|
||||||
use searchers::Searcher;
|
use searchers::Searcher;
|
||||||
|
|
||||||
use hyper;
|
use scryfall;
|
||||||
use hyper::Client;
|
use scryfall::{Scryfall, Card};
|
||||||
|
|
||||||
use serde_json;
|
|
||||||
use serde_json::Value;
|
|
||||||
|
|
||||||
use retry;
|
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;
|
||||||
const RETRY_WAIT_MILLIS: u64 = 500;
|
const RETRY_WAIT_MILLIS: u64 = 500;
|
||||||
|
|
||||||
#[derive(Debug)]
|
impl Link for Card {
|
||||||
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 {
|
|
||||||
fn label (&self) -> &str {
|
fn label (&self) -> &str {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
fn url (&self) -> &str {
|
fn url (&self) -> &str {
|
||||||
&self.url
|
&self.uri
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_any (&self) -> &Any {
|
fn as_any (&self) -> &Any {
|
||||||
@ -48,69 +30,45 @@ impl Link for MtgCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct MtgSearcher {
|
pub struct MtgSearcher {
|
||||||
client: Client
|
scryfall: Scryfall
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MtgSearcher {
|
impl MtgSearcher {
|
||||||
pub fn new () -> MtgSearcher {
|
pub fn new () -> MtgSearcher {
|
||||||
MtgSearcher {
|
MtgSearcher {
|
||||||
client: Client::new()
|
scryfall: Scryfall::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_search (&self, name: &str) -> Result<String, Error> {
|
fn do_search (&self, query: &str) -> Result<Option<Card>, Error> {
|
||||||
let mut contents = String::new();
|
let mut result = retry(Fixed::from_millis(RETRY_WAIT_MILLIS).take(NUM_RETRIES), || {
|
||||||
let api_url = &format!("https://api.magicthegathering.io/v1/cards?name={}", name);
|
self.scryfall.search(query, None, 0)
|
||||||
let mut response = retry(Fixed::from_millis(RETRY_WAIT_MILLIS).take(NUM_RETRIES), || {
|
|
||||||
self.client.get(api_url).send()
|
|
||||||
})?;
|
})?;
|
||||||
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> {
|
impl Searcher<Card> for MtgSearcher {
|
||||||
let parsed: Value = serde_json::from_str(&page)?;
|
fn exact_search (&self, name: &str) -> Option<Card> {
|
||||||
for entry in parsed["cards"].as_array().unwrap_or(&vec![]) {
|
let search = format!(r#"!{}"#, name);
|
||||||
if entry["imageUrl"].as_str().is_some() {
|
self.do_search(&search).unwrap_or(None)
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Error {
|
enum Error {
|
||||||
Http(hyper::error::Error),
|
Client(scryfall::Error),
|
||||||
Io(std::io::Error),
|
Io(std::io::Error),
|
||||||
Json(serde_json::Error),
|
|
||||||
Other(String)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<hyper::error::Error> for Error {
|
impl From<scryfall::Error> for Error {
|
||||||
fn from (error: hyper::error::Error) -> Error {
|
fn from (error: scryfall::Error) -> Error {
|
||||||
Error::Http(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 {
|
impl From<retry::Error<scryfall::Error>> for Error {
|
||||||
fn from (err: retry::Error<hyper::Error>) -> Error {
|
fn from (err: retry::Error<scryfall::Error>) -> Error {
|
||||||
match err {
|
match err {
|
||||||
retry::Error::Operation { error, total_delay, tries } => {
|
retry::Error::Operation { error, total_delay, tries } => {
|
||||||
Error::Http(error)
|
Error::Client(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user