Skip to content

Commit

Permalink
chore: make network printer work
Browse files Browse the repository at this point in the history
  • Loading branch information
dni committed Jan 2, 2025
1 parent f253d4d commit 70d3ccd
Show file tree
Hide file tree
Showing 11 changed files with 236 additions and 32 deletions.
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,25 @@
# Pay 2 Print Extension - <small>[repository](https://github.com/lnbits/pay2print) extension</small>


## share a printer via the network on cups
https://www.cups.org/doc/sharing.html


### 1. install cups and configure printer
```
apt-get install cups
systemctl start cups
systemctl enable cups
lpadmin -p MyPrinterName -o printer-is-shared=true
# set default printer
# lpoptions -d MyPrinterName
cupsctl --share-printers
```

### server where you access the sharedprinter via the network
```
apt-get install cups-client
# check if printer is shared
lpstat -h 10.5.5.2 -a
```
6 changes: 3 additions & 3 deletions crud.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from datetime import datetime, timezone
from typing import Optional

from lnbits.db import Database
from lnbits.db import Connection, Database

from .models import CreatePrinter, Print, Printer

Expand All @@ -18,9 +18,9 @@ async def create_print(payment_hash: str, printer_id: str, file_name: str) -> Pr
return _print


async def update_print(_print: Print) -> Print:
async def update_print(_print: Print, conn: Optional[Connection] = None) -> Print:
_print.updated_at = datetime.now(timezone.utc)
await db.update("pay2print.print", _print)
await (conn or db).update("pay2print.print", _print)
return _print


Expand Down
18 changes: 8 additions & 10 deletions helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@

upload_dir = Path(settings.lnbits_data_folder, "uploads")

cmd_check_default_printer = ["lpstat", "-d"]
cmd_print = "lpr"


class PrinterError(Exception):
"""Error is thrown we we cannot connect to the printer."""
Expand All @@ -32,19 +29,20 @@ def print_file_path(file_name: str) -> Path:
return Path(upload_dir, file_name)


def check_printer():
def check_printer(host: str, printer_name: str):
try:
lines = run_command(cmd_check_default_printer)
if len(lines) == 0:
raise PrinterError("No default printer found")
logger.debug(f"Default printer: {lines[0]}")
lines = run_command(["lpstat", "-h", host, "-a"])
logger.debug(f"lpstat -h {host} -a: {lines}")
if printer_name not in "\n".join(lines):
raise PrinterError(f"Printer {printer_name} not found")
except Exception as e:
raise PrinterError(f"Error checking default printer: {e}") from e


def print_file(file_name: str):
def print_file(host: str, printer_name, file_name: str):
path = print_file_path(file_name)
run_command([cmd_print, str(path)])
logger.debug(f"Printing {path} to {host} {printer_name}")
run_command(["lp", "-h", host, "-d", printer_name, str(path)])


def run_command(command: list[str]) -> list[str]:
Expand Down
5 changes: 5 additions & 0 deletions models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
from pydantic import BaseModel, Field


class UploadPayment(BaseModel):
payment_hash: str
payment_request: str


class PrintStatus(str, Enum):
WAITING = "waiting"
PRINTING = "printing"
Expand Down
22 changes: 22 additions & 0 deletions services.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import asyncio

from .crud import db, update_print
from .helpers import check_printer, print_file
from .models import Print, Printer, PrintStatus


async def print_service(_print: Print, printer: Printer) -> None:
check_printer(printer.host, printer.name)
async with db.connect() as conn:
_print.print_status = PrintStatus.PRINTING
await update_print(_print, conn=conn)
try:
print_file(printer.host, printer.name, _print.file)
await asyncio.sleep(5) # simulate printing time
_print.print_status = PrintStatus.SUCCESS
await update_print(_print, conn=conn)
return
except Exception as exc:
_print.print_status = PrintStatus.FAILED
await update_print(_print, conn=conn)
raise exc
40 changes: 40 additions & 0 deletions static/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,46 @@ window.app = Vue.createApp({
})
.catch(LNbits.utils.notifyApiError)
},
testPrinter(printer_id) {
LNbits.api
.request(
'GET',
`${this.printerUrl}/check/${printer_id}`,
this.g.user.wallets[0].adminkey
)
.then(response => {
console.log(response)
Quasar.Notify.create({
message: 'Printer check successful',
color: 'positive',
})
})
.catch(LNbits.utils.notifyApiError)
},
openPrint(print_id) {
LNbits.api
.request(
'GET',
`${this.printUrl}/print/${print_id}`,
this.g.user.wallets[0].adminkey
)
.then(response => {
this.prints = response.data
})
.catch(LNbits.utils.notifyApiError)
},
deletePrint(id) {
LNbits.api
.request(
'DELETE',
`${this.printUrl}/${id}`,
this.g.user.wallets[0].adminkey
)
.then(_ => {
this.getPrints(this.printer)
})
.catch(LNbits.utils.notifyApiError)
},
getPrinters() {
LNbits.api
.request('GET', this.printerUrl, this.g.user.wallets[0].inkey)
Expand Down
21 changes: 16 additions & 5 deletions static/js/public.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,26 @@ window.app = Vue.createApp({
data() {
return {
invoice: null,
invoiceAmount: amount + ' sat',
invoiceAmount: `${amount} sat per print`,
paid: false
}
},
methods: {
reset() {
this.invoice = null
this.paid = false
},
uploaded(e) {
console.log('uploaded', e.xhr)
this.invoice = e.xhr.response
const data = JSON.parse(e.xhr.response)
this.invoice = data.payment_request
const ws = new WebSocket(`${websocketUrl}/${data.payment_hash}`)
ws.onmessage = ev => {
const data = JSON.parse(ev.data)
if (data.pending === false) {
this.paid = true
ws.close()
}
}
}
},
created() {}
}
})
18 changes: 16 additions & 2 deletions tasks.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import asyncio

from lnbits.core.models import Payment
from lnbits.core.models import Payment, PaymentState
from lnbits.tasks import register_invoice_listener
from loguru import logger

from .crud import get_print, get_printer, update_print
from .services import print_service


async def wait_for_paid_invoices():
invoice_queue = asyncio.Queue()
Expand All @@ -17,4 +20,15 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment) -> None:
if payment.extra.get("tag") == "pay2print":
logger.info("pay2print extension received payment")
logger.debug(payment)
print_id = payment.extra.get("print_id")
assert print_id, "Print ID not found."
_print = await get_print(print_id)
assert _print, "Print not found."
printer = await get_printer(_print.printer)
assert printer, "Printer not found."
_print.payment_status = PaymentState.SUCCESS
await update_print(_print)
try:
await print_service(_print, printer)
except Exception as exc:
logger.error(f"Error printing {_print.id}: {exc}")
29 changes: 28 additions & 1 deletion templates/pay2print/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ <h5 class="text-subtitle1 q-my-none">Printers</h5>
flat
dense
size="xs"
@click="openTestPrint(props.row.id)"
@click="testPrinter(props.row.id)"
target="_blank"
icon="print"
color="primary"
Expand Down Expand Up @@ -198,6 +198,8 @@ <h5 class="text-subtitle1 q-my-none">Prints</h5>
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th style="width: 2%"></q-th>
<q-th style="width: 2%"></q-th>
<q-th
v-for="col in props.cols"
:key="col.name"
Expand All @@ -211,6 +213,31 @@ <h5 class="text-subtitle1 q-my-none">Prints</h5>

<template v-slot:body="props">
<q-tr :props="props">
<q-td>
<q-btn
flat
dense
size="xs"
@click="openPrint(props.row.id)"
target="_blank"
icon="print"
color="primary"
>
<q-tooltip>Print</q-tooltip>
</q-btn>
</q-td>
<q-td>
<q-btn
flat
dense
size="xs"
@click="deletePrint(props.row.id)"
icon="cancel"
color="pink"
>
<q-tooltip>Delete Print</q-tooltip>
</q-btn>
</q-td>
<q-td
v-for="col in props.cols"
:key="col.name"
Expand Down
36 changes: 29 additions & 7 deletions templates/pay2print/public.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
<q-page>
<q-card class="q-mt-md">
<q-card-section v-if="invoice == null" class="q-mb-sm text-center">
<h2 class="text-h6">Upload a pdf file to print</h2>
<h2 class="text-h5">
Upload a pdf file to print
<p v-text="invoiceAmount"></p>
</h2>
<q-uploader
class="q-ml-auto q-mr-auto"
multiple="false"
Expand All @@ -18,24 +21,43 @@ <h2 class="text-h6">Upload a pdf file to print</h2>
class="q-mb-sm text-center"
>
<h2 class="text-h6">Pay this invoice to print!</h2>
<h6 v-text="invoiceAmount"></h6>
<lnbits-qrcode :value="invoice"></lnbits-qrcode>
<q-btn
icon="content_copy"
@click="copyText(invoice)"
size="1em"
color="grey"
class="q-mb-xs cursor-pointer"
color="primary"
class="q-mb-xs q-mt-sm cursor-pointer"
>Copy invoice</q-btn
>
<q-btn
icon="refresh"
@click="reset()"
size="1em"
color="secondary"
class="q-ml-md q-mb-xs q-mt-sm cursor-pointer"
>Reset
</q-btn>
</q-card-section>
<q-card-section
v-if="invoice != null && paid == true"
class="q-mb-sm text-center"
>
<h2 class="text-h6">Invoice paid, document is printing!</h2>
<q-icon name="done" size="3em" color="green" />
<q-icon name="print" size="3em" color="grey" />
<h2 class="text-h6">
<q-icon name="done" size="3em" color="green"></q-icon>
Invoice paid, document is printing!
</h2>
<div>
<q-icon name="print" size="3em" color="grey"></q-icon>
</div>
<q-btn
icon="refresh"
@click="reset()"
size="1em"
color="secondary"
class="q-mt-sm q-mb-xs cursor-pointer"
>Reset
</q-btn>
</q-card-section>
</q-card>
</q-page>
Expand Down
Loading

0 comments on commit 70d3ccd

Please sign in to comment.