src/receipt_printer.rs
+0
-152
diff --git a/src/receipt_printer.rs b/src/receipt_printer.rs
deleted file mode 100644
index e9b71de..0000000
@@ -1,152 +0,0 @@
use std::{fmt::Display, sync::Arc};
use escpos::{
driver::NetworkDriver,
errors::PrinterError,
printer::Printer,
utils::{BitImageOption, BitImageSize, Protocol},
};
use tokio::sync::{mpsc, oneshot};
pub struct ReceiptPrinter {
sender: mpsc::UnboundedSender<EscposPrinterRequest>,
}
impl ReceiptPrinter {
pub const IMAGE_WIDTH_PIXEL: u32 = 72 * 8;
pub const IMAGE_WIDTH_CM: f32 = 7.2;
pub const IMAGE_WIDTH_PT: f32 = Self::IMAGE_WIDTH_CM / 0.03527;
pub const IMAGE_PIXELS_PER_PT: f32 = Self::IMAGE_WIDTH_PIXEL as f32 / Self::IMAGE_WIDTH_PT;
pub fn init(host: String, port: u16) -> Self {
let (sender, receiver) = mpsc::unbounded_channel();
EscposPrinterActor {
host,
port,
printer: None,
receiver,
}
.run();
Self { sender }
}
pub async fn print_image(&self, image: Arc<[u8]>) -> Result<(), ReceiptPrinterError> {
let (responder, receiver) = oneshot::channel();
self.sender
.send(EscposPrinterRequest::PrintImage(image, responder))
.map_err(ReceiptPrinterError::send)?;
receiver
.await
.map_err(ReceiptPrinterError::receive)?
.map_err(ReceiptPrinterError::printer)
}
}
struct EscposPrinterActor {
host: String,
port: u16,
printer: Option<EscposPrinter>,
receiver: mpsc::UnboundedReceiver<EscposPrinterRequest>,
}
enum EscposPrinterRequest {
PrintImage(Arc<[u8]>, oneshot::Sender<Result<(), PrinterError>>),
}
impl EscposPrinterActor {
fn run(mut self) {
tokio::spawn(async move {
while let Some(request) = self.receiver.recv().await {
let response_result = match request {
EscposPrinterRequest::PrintImage(image, responder) => {
responder.send(self.print_image(&image))
}
};
if let Err(error) = response_result {
println!("Could not respond to request: {error:?}");
}
}
});
}
fn print_image(&mut self, image: &[u8]) -> Result<(), PrinterError> {
let printer = self.ensure_printer_connection()?;
printer.print_image(image)
}
fn ensure_printer_connection<'s>(&'s mut self) -> Result<&'s mut EscposPrinter, PrinterError> {
let printer = match self.printer.take() {
Some(printer) => printer,
None => EscposPrinter::open(&self.host, self.port)?,
};
Ok(self.printer.insert(printer))
}
}
struct EscposPrinter {
printer: Printer<NetworkDriver>,
}
impl EscposPrinter {
fn open(host: &str, port: u16) -> Result<Self, PrinterError> {
let driver = NetworkDriver::open(host, port, None)?;
Ok(Self {
printer: Printer::new(driver, Protocol::default(), None),
})
}
fn print_image(&mut self, image: &[u8]) -> Result<(), PrinterError> {
self.printer.init()?;
self.printer.bit_image_from_bytes_option(
image,
BitImageOption::new(
Some(ReceiptPrinter::IMAGE_WIDTH_PIXEL),
None,
BitImageSize::Normal,
)?,
)?;
self.printer.print_cut()?;
Ok(())
}
}
pub struct ReceiptPrinterError {
variant: ReceiptPrinterErrorVariants,
}
impl ReceiptPrinterError {
fn send(send_error: mpsc::error::SendError<EscposPrinterRequest>) -> Self {
Self {
variant: ReceiptPrinterErrorVariants::Send(send_error),
}
}
fn receive(recv_error: oneshot::error::RecvError) -> Self {
Self {
variant: ReceiptPrinterErrorVariants::Receive(recv_error),
}
}
fn printer(printer_error: PrinterError) -> Self {
Self {
variant: ReceiptPrinterErrorVariants::Printer(printer_error),
}
}
}
enum ReceiptPrinterErrorVariants {
Send(mpsc::error::SendError<EscposPrinterRequest>),
Receive(oneshot::error::RecvError),
Printer(PrinterError),
}
impl Display for ReceiptPrinterError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.variant {
ReceiptPrinterErrorVariants::Send(send_error) => send_error.fmt(f),
ReceiptPrinterErrorVariants::Receive(recv_error) => recv_error.fmt(f),
ReceiptPrinterErrorVariants::Printer(printer_error) => printer_error.fmt(f),
}
}
}
src/receipt_printer/escpos_printer.rs
+35
-0
diff --git a/src/receipt_printer/escpos_printer.rs b/src/receipt_printer/escpos_printer.rs
new file mode 100644
index 0000000..2d2126c
@@ -0,0 +1,35 @@
use escpos::{
driver::NetworkDriver,
errors::PrinterError,
printer::Printer,
utils::{BitImageOption, BitImageSize, Protocol},
};
use crate::receipt_printer::ReceiptPrinter;
pub struct EscposPrinter {
printer: Printer<NetworkDriver>,
}
impl EscposPrinter {
pub fn open(host: &str, port: u16) -> Result<Self, PrinterError> {
let driver = NetworkDriver::open(host, port, None)?;
Ok(Self {
printer: Printer::new(driver, Protocol::default(), None),
})
}
pub fn print_image(&mut self, image: &[u8]) -> Result<(), PrinterError> {
self.printer.init()?;
self.printer.bit_image_from_bytes_option(
image,
BitImageOption::new(
Some(ReceiptPrinter::IMAGE_WIDTH_PIXEL),
None,
BitImageSize::Normal,
)?,
)?;
self.printer.print_cut()?;
Ok(())
}
}
src/receipt_printer/mod.rs
+40
-0
diff --git a/src/receipt_printer/mod.rs b/src/receipt_printer/mod.rs
new file mode 100644
index 0000000..da4ace2
@@ -0,0 +1,40 @@
mod escpos_printer;
mod receipt_printer_actor;
mod receipt_printer_error;
use std::sync::Arc;
use tokio::sync::{mpsc, oneshot};
use self::receipt_printer_actor::{EscposPrinterActor, EscposPrinterRequest};
use self::receipt_printer_error::ReceiptPrinterError;
pub struct ReceiptPrinter {
sender: mpsc::UnboundedSender<EscposPrinterRequest>,
}
impl ReceiptPrinter {
pub const IMAGE_WIDTH_PIXEL: u32 = 72 * 8;
pub const IMAGE_WIDTH_CM: f32 = 7.2;
pub const IMAGE_WIDTH_PT: f32 = Self::IMAGE_WIDTH_CM / 0.03527;
pub const IMAGE_PIXELS_PER_PT: f32 = Self::IMAGE_WIDTH_PIXEL as f32 / Self::IMAGE_WIDTH_PT;
pub fn init(host: String, port: u16) -> Self {
let (sender, receiver) = mpsc::unbounded_channel();
EscposPrinterActor::run(host, port, receiver);
Self { sender }
}
pub async fn print_image(&self, image: Arc<[u8]>) -> Result<(), ReceiptPrinterError> {
let (responder, receiver) = oneshot::channel();
self.sender
.send(EscposPrinterRequest::PrintImage(image, responder))
.map_err(ReceiptPrinterError::send)?;
receiver
.await
.map_err(ReceiptPrinterError::receive)?
.map_err(ReceiptPrinterError::printer)
}
}
src/receipt_printer/receipt_printer_actor.rs
+55
-0
diff --git a/src/receipt_printer/receipt_printer_actor.rs b/src/receipt_printer/receipt_printer_actor.rs
new file mode 100644
index 0000000..d2b8f44
@@ -0,0 +1,55 @@
use std::sync::Arc;
use escpos::errors::PrinterError;
use tokio::sync::{mpsc, oneshot};
use super::escpos_printer::EscposPrinter;
pub struct EscposPrinterActor {
host: String,
port: u16,
printer: Option<EscposPrinter>,
receiver: mpsc::UnboundedReceiver<EscposPrinterRequest>,
}
pub enum EscposPrinterRequest {
PrintImage(Arc<[u8]>, oneshot::Sender<Result<(), PrinterError>>),
}
impl EscposPrinterActor {
pub fn run(host: String, port: u16, receiver: mpsc::UnboundedReceiver<EscposPrinterRequest>) {
let mut actor = Self {
host,
port,
printer: None,
receiver,
};
tokio::spawn(async move {
while let Some(request) = actor.receiver.recv().await {
let response_result = match request {
EscposPrinterRequest::PrintImage(image, responder) => {
responder.send(actor.print_image(&image))
}
};
if let Err(error) = response_result {
println!("Could not respond to request: {error:?}");
}
}
});
}
pub fn print_image(&mut self, image: &[u8]) -> Result<(), PrinterError> {
let printer = self.ensure_printer_connection()?;
printer.print_image(image)
}
fn ensure_printer_connection<'s>(&'s mut self) -> Result<&'s mut EscposPrinter, PrinterError> {
let printer = match self.printer.take() {
Some(printer) => printer,
None => EscposPrinter::open(&self.host, self.port)?,
};
Ok(self.printer.insert(printer))
}
}
src/receipt_printer/receipt_printer_error.rs
+44
-0
diff --git a/src/receipt_printer/receipt_printer_error.rs b/src/receipt_printer/receipt_printer_error.rs
new file mode 100644
index 0000000..10285c1
@@ -0,0 +1,44 @@
use std::fmt::Display;
use escpos::errors::PrinterError;
use tokio::sync::{mpsc, oneshot};
use super::receipt_printer_actor::EscposPrinterRequest;
pub struct ReceiptPrinterError {
variant: ReceiptPrinterErrorVariants,
}
impl ReceiptPrinterError {
pub fn send(send_error: mpsc::error::SendError<EscposPrinterRequest>) -> Self {
Self {
variant: ReceiptPrinterErrorVariants::Send(send_error),
}
}
pub fn receive(recv_error: oneshot::error::RecvError) -> Self {
Self {
variant: ReceiptPrinterErrorVariants::Receive(recv_error),
}
}
pub fn printer(printer_error: PrinterError) -> Self {
Self {
variant: ReceiptPrinterErrorVariants::Printer(printer_error),
}
}
}
enum ReceiptPrinterErrorVariants {
Send(mpsc::error::SendError<EscposPrinterRequest>),
Receive(oneshot::error::RecvError),
Printer(PrinterError),
}
impl Display for ReceiptPrinterError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.variant {
ReceiptPrinterErrorVariants::Send(send_error) => send_error.fmt(f),
ReceiptPrinterErrorVariants::Receive(recv_error) => recv_error.fmt(f),
ReceiptPrinterErrorVariants::Printer(printer_error) => printer_error.fmt(f),
}
}
}