Implementing network/file printer


So I have a food-order platform (written in Actix) where restaurants can display their menu and people can order food. Until now the incoming orders were displayed in a dashboard for the restaurants. The problem that occurred was that not all restaurants keep their dashboard open and they actually prefer to just have a printed order-receipt for an order.

To solve this I made a desktop-app that the restaurants need to install once on their cash-register system and which automatically prints an order receipt when an order is received. This is almost finished.

I am using Recibo to print the ESC/POS labels. The user has to select his thermal printer in my app. To retrieve the available printers to show them in a dropdown I am using a function like this:

pub struct Printer {
    pub name: String,
    pub driver_name: String,
    pub port: String,
    pub fn printers() -> std::vec::Vec<system::Printer> {
        let mut printers : std::vec::Vec<system::Printer> = std::vec::Vec::new();

        let cmd = std::process::Command::new("cmd")
            .args(["/C", "wmic printer get Name,DriverName,Portname"])

       // Interpret the result from the command retrieving the printers,
       // put them in a Printer-object and return the list


(This is for Windows, Unix/MacOS has a similar function).

To initialize the printer I am using Recibo like this:

    let driver = FileDriver::new(PRINTER_STRING).unwrap();
    let mut printer = Printer::open(driver).unwrap();

If the printer is connected by a cable PRINTER_STRING could be for example COM3:. Recibo can then print to the receipt to the port as if it were a file.

But the user could also select a network printer. It would be ideal if there was a way to write to those network printers as if it were files but that is not the case.

These are the issues I encountered:

  • Recibo has two drivers. A file driver which opens the given printer like this let file = OpenOptions::new().read(true).write(true).open(path)?; and a Network Driver opening the given printer like this let stream = TcpStream::connect((host, port))?;.
  • The Network Driver of Recibo for example does not support network printers shared using smb://.
  • The info about the printers I can retrieve using the commands is basic. In Unix I currently only retrieve the printer names.

So to keep things simple I came up with the following. I only use the File Driver in Recibo, even when a network printer is selected. Using the File Driver I write the content of the receipt to a file.

let printer_as_file = format!("printer_content_{}.txt", order_id);

let driver = FileDriver::new(printer_as_file.to_string()).unwrap();
let mut printer = Printer::open(driver).unwrap();

When the whole receipt is formatted and parsed, I simply launch the following command:

std::process::Command::new("./").arg(printer_name).arg(printer_as_file).status().unwrap(); is a basic script which allows me to print the generated file for the receipt by using only the name of the printer.

lpr -P $1 $2
rm $2

(For Unix, for Windows there is a separate script).


  1. I use the File Driver of Recibo to output the content of the receipt from the incoming order in a file printer_content_<unique_id>.txt.
  2. I use the command lpr to print the file to the selected printer. This way I do not have to retrieve the IP and port of the printer in case it is a network printer.
  3. When it is printed the file printer_content_<unique_id>.txt gets deleted.

Solving it this way saves me a lot of headache trying to implement the code to handle the different kind of printers (connected by cable/port, network, smb://,...).

Is this a solid way to solve this issue or are there better suggestions?

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.