initial commit

This commit is contained in:
Niklas Kapelle 2024-02-25 12:22:24 +01:00
commit 4e60216b8e
Signed by: niklas
GPG Key ID: 4EB651B36D841D16
10 changed files with 3360 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

1551
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

12
Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "printer-api"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
escpos = { version = "0.6.2", features = ["full"] }
graphql_client = { version = "0.13.0", features = ["graphql_query_derive" , "reqwest-blocking"] }
reqwest = { version = "0.11.24", features = ["json", "blocking"] }
serde = "1.0.196"

7
gql/GetItem.graphql Normal file
View File

@ -0,0 +1,7 @@
query GetItem($index: String!) {
magicItem(index: $index){
name,
rarity,
desc
}
}

19
gql/GetSpell.graphql Normal file
View File

@ -0,0 +1,19 @@
query GetSpell($index: String!){
spell(index: $index){
name,
level,
school {
name
}
desc,
components,
duration,
ritual,
range,
casting_time,
area_of_effect {
size
type
}
}
}

1446
gql/schema.graphql Normal file

File diff suppressed because it is too large Load Diff

142
src/api_client.rs Normal file
View File

@ -0,0 +1,142 @@
use crate::types::{Item, Spell};
use graphql_client::{GraphQLQuery, QueryBody, Response};
use std::error::Error;
// https://studio.apollographql.com/sandbox?endpoint=https%3A%2F%2Fwww.dnd5eapi.co%2Fgraphql
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "gql/schema.graphql",
query_path = "gql/GetSpell.graphql",
response_derives = "Debug"
)]
struct GetSpell;
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "gql/schema.graphql",
query_path = "gql/GetItem.graphql",
response_derives = "Debug"
)]
struct GetItem;
fn perform_request<Q>(
request_body: QueryBody<Q::Variables>,
) -> Result<Response<Q::ResponseData>, Box<dyn Error>>
where
Q: GraphQLQuery,
{
let client = reqwest::blocking::Client::new();
let res = client
.post("https://www.dnd5eapi.co/graphql")
.json(&request_body)
.send()?;
let response_body: Response<Q::ResponseData> = res.json()?;
return Ok(response_body);
}
fn spell_component_to_string(c: &get_spell::SpellComponent) -> String {
match c {
get_spell::SpellComponent::M => String::from("M"),
get_spell::SpellComponent::V => String::from("V"),
get_spell::SpellComponent::S => String::from("S"),
get_spell::SpellComponent::Other(s) => String::from(s),
}
}
fn rarity_to_string(r: &get_item::MagicItemRarity) -> String {
match r {
get_item::MagicItemRarity::ARTIFACT => String::from("ARTIFACT"),
get_item::MagicItemRarity::LEGENDARY => String::from("LEGENDARY"),
get_item::MagicItemRarity::VERY_RARE => String::from("VERY_RARE"),
get_item::MagicItemRarity::RARE => String::from("RARE"),
get_item::MagicItemRarity::UNCOMMON => String::from("UNCOMMON"),
get_item::MagicItemRarity::COMMON => String::from("COMMON"),
get_item::MagicItemRarity::VARIES => String::from("VARIES"),
get_item::MagicItemRarity::Other(s) => String::from(s),
}
}
pub fn get_spell(index: &str) -> Result<Spell, Box<dyn Error>> {
let vars = get_spell::Variables {
index: index.into(),
};
let body = GetSpell::build_query(vars);
let res = perform_request::<GetSpell>(body)?;
match res.data {
Some(data) => match data.spell {
Some(spell) => {
let rtn = Spell {
name: spell.name,
level: spell.level,
school: spell.school.name,
range: spell.range,
desc: spell.desc.join(" "),
components: match spell.components {
Some(components) => {
Some(components
.iter()
.flatten()
.map(spell_component_to_string)
.collect::<Vec<String>>().join(" ")
)
}
_ => None,
},
duration: spell.duration,
ritual: spell.ritual,
casting_time: spell.casting_time,
};
return Ok(rtn);
}
_ => {
return Err(Box::from("Spell not found"));
}
},
_ => {
return Err(Box::from("Spell not found"));
}
}
}
pub fn get_item(index: &str) -> Result<Item, Box<dyn Error>>{
let vars = get_item::Variables {
index: index.into(),
};
let body = GetItem::build_query(vars);
let res = perform_request::<GetItem>(body)?;
match res.data {
Some(data) => {
match data.magic_item {
Some(item) => {
let rtn = Item{
name: item.name,
rarity: rarity_to_string(&item.rarity),
desc: item.desc.join(" ")
};
return Ok(rtn);
}
None => {
return Err(Box::from("Item not found"));
}
}
}
None => {
return Err(Box::from("Item not found"));
}
}
}

35
src/main.rs Normal file
View File

@ -0,0 +1,35 @@
use std::path::Path;
mod print;
mod api_client;
mod types;
use escpos::{driver::{ConsoleDriver, FileDriver}, errors::PrinterError, printer::Printer, utils::Protocol};
// https://www.dnd5eapi.co/graphql
fn run() -> Result<(),PrinterError> {
// let driver = FileDriver::open(Path::new("/dev/usb/lp0")).unwrap();
let driver = ConsoleDriver::open(true);
let mut printer = Printer::new(driver, Protocol::default());
printer.init()?;
print::print_test_page(&mut printer)?;
return Ok(());
}
fn main(){
let spell = api_client::get_spell("eldritch-blast").unwrap();
let driver = FileDriver::open(Path::new("/dev/usb/lp0")).unwrap();
let mut printer = Printer::new(driver, Protocol::default());
printer.init().unwrap();
print::print_spell(&mut printer, &spell).unwrap();
println!("{:?}",spell);
}

129
src/print.rs Normal file
View File

@ -0,0 +1,129 @@
use escpos::{driver::Driver, errors::PrinterError, printer::Printer, utils::JustifyMode};
use crate::types::Spell;
const WIDTH: usize = 32;
pub fn print_test_page<D: Driver>(printer: &mut Printer<D>) -> Result<(), PrinterError> {
printer
.writeln("---Printer Test Page---")?
.bold(true)?
.writeln("This text should be bold.")?
.bold(false)?
.underline(escpos::utils::UnderlineMode::Single)?
.writeln("This text should be single underline.")?
.underline(escpos::utils::UnderlineMode::Double)?
.writeln("This text should be double underline.")?
.underline(escpos::utils::UnderlineMode::None)?
.double_strike(true)?
.writeln("This text should be double striked.")?
.double_strike(true)?
.writeln("Text alignment")?
.justify(JustifyMode::CENTER)?
.writeln("CENTER")?
.justify(JustifyMode::RIGHT)?
.writeln("RIGHT")?
.justify(JustifyMode::LEFT)?
.size(1, 1)?
.writeln("size 1")?
.size(5, 5)?
.writeln("size 5")?
.reset_size()?
.font(escpos::utils::Font::A)?
.write("Font A ")?
.font(escpos::utils::Font::B)?
.write("Font B ")?
.font(escpos::utils::Font::C)?
.writeln("Font C")?
.font(escpos::utils::Font::A)?
.flip(true)?
.writeln("Fliped")?
.flip(false)?
.line_spacing(8)?
.writeln("Line")?
.writeln("Spacing")?
.reset_line_spacing()?
.upside_down(true)?
.writeln("Upside down")?
.upside_down(false)?
// Barcodes
.writeln("EAN-13 (978020137962)")?
.ean13("978020137962")?
.writeln("EAN-8 (9031101)")?
.ean8("9031101")?
.writeln("UPC-A")?
.upca("72527273070")?
.writeln("CODE-39")?
.code39("1234")?
.writeln("CODABAR")?
.writeln("1234")?
.writeln("ITF")?
.itf("1234")?
// 2D Codes
.writeln("QR Code")?
.qrcode("Hello world")?
.writeln("2D GS1 DataBar")?
.gs1_databar_2d("1234567890123")?
.writeln("pdf417")?
.pdf417("Hello world")?
.writeln("Maxi code")?
.maxi_code("Hello world")?
.writeln("Data matrix")?
.data_matrix("Hello world")?
.writeln("aztec")?
.aztec("Hello world")?
// Image
.writeln("raster image")?
// .bit_image("./rust-logo-small.png")?
.print()?;
return Ok(());
}
fn left_right_print<D: Driver>(printer: &mut Printer<D>,left: &str, right: &str ) -> Result<(), PrinterError> {
printer
.write(left)?
.write(&".".repeat(WIDTH - left.len() - right.len()))?
.writeln(right)?;
return Ok(());
}
pub fn print_spell<D: Driver>(printer: &mut Printer<D>, spell: &Spell) -> Result<(), PrinterError> {
printer
.size(4, 4)?
.writeln(&spell.name)?
.reset_size()?
.line_spacing(1)?;
if spell.level > 0 {
if spell.ritual {
printer.writeln(&format!("Lvl. {} {} (ritual)", spell.level, spell.school))?;
}else{
printer.writeln(&format!("Lvl. {} {}", spell.level, spell.school))?;
}
} else {
printer.writeln(&format!("{} cantrip", spell.school))?;
}
printer.feed()?;
match &spell.components {
Some(comp) => {
left_right_print(printer, "Components:", &comp)?;
}
_ => {}
}
left_right_print(printer, "Casting time:", &spell.casting_time)?;
left_right_print(printer, "Range:", &spell.range)?;
left_right_print(printer, "Duration:", &spell.duration)?;
printer
.reset_line_spacing()?
.write(&spell.desc)?
.feeds(3)?
.print()?;
return Ok(());
}

18
src/types.rs Normal file
View File

@ -0,0 +1,18 @@
#[derive(Debug)]
pub struct Spell{
pub name: String,
pub level: i64,
pub range: String,
pub school: String,
pub desc: String,
pub components: Option<String>,
pub duration: String,
pub ritual: bool,
pub casting_time: String,
}
pub struct Item {
pub name: String,
pub rarity: String,
pub desc: String,
}