diff --git a/docker-compose.printer.dev.yml b/docker-compose.printer.dev.yml new file mode 100644 index 0000000..af422cd --- /dev/null +++ b/docker-compose.printer.dev.yml @@ -0,0 +1,20 @@ +version: '2' +services: + sce-printer: + container_name: sce-printer-dev + build: + context: . + dockerfile: ./printer/Dockerfile.printer.dev + ports: + # we use port 14000 as that is what the website expects + # the printing server to be running on + - 14000:14000 + volumes: + - ./config:/app/config + - ./printer:/app/printer + - ./tmp:/tmp + command: + - --development + - --port=14000 + - --dont-delete-pdfs + - --config-json-path=/app/config/config.json diff --git a/printer/Dockerfile.printer.dev b/printer/Dockerfile.printer.dev new file mode 100644 index 0000000..9510aab --- /dev/null +++ b/printer/Dockerfile.printer.dev @@ -0,0 +1,23 @@ +# Base image from https://github.com/DrPsychick/docker-cups-airprint +# Docker images are here https://hub.docker.com/r/drpsychick/airprint-bridge/tags +FROM drpsychick/airprint-bridge:jammy + +WORKDIR /app + +RUN apt-get update + +RUN apt install -y python3 python3-pip python3-venv + +# Create the virtual environment with Python +RUN python3 -m venv /opt/venv + +# Set the virtual environment as the default Python environment +ENV PATH="/opt/venv/bin:$PATH" + +COPY ./printer/requirements.txt /app/printer/requirements.txt + +RUN /opt/venv/bin/pip install -r /app/printer/requirements.txt + +EXPOSE 9000 + +ENTRYPOINT ["./printer/what_dev.sh"] \ No newline at end of file diff --git a/printer/modules/gerard.py b/printer/modules/gerard.py index 11c7feb..cde3d46 100644 --- a/printer/modules/gerard.py +++ b/printer/modules/gerard.py @@ -5,10 +5,11 @@ import logging import shlex import subprocess - +import datetime LP_COMMAND = """ lp \ + -H {hold_time} \ -n {num_copies} {maybe_page_range} \ -o sides={sides} \ -o media=na_letter_8.5x11in \ @@ -36,7 +37,6 @@ def __next__(self): print_job_suffix = IDIterator() - def create_print_job( num_copies, maybe_page_range, @@ -44,8 +44,16 @@ def create_print_job( printer_name, file_path, is_development_mode=False, + # no_dev_printer=False ): + hold_time = "immediate" + if is_development_mode: + future_datetime = datetime.datetime.fromtimestamp(datetime.datetime.utcnow().timestamp() + 5) + hold_time = f"{future_datetime.hour}:{future_datetime.minute}:{future_datetime.second}" + + command = LP_COMMAND.format( + hold_time=hold_time, num_copies=num_copies, maybe_page_range=maybe_page_range, sides=sides, @@ -59,6 +67,7 @@ def create_print_job( ) job_id = f"HP_LaserJet_p2015dn_Right-{next(print_job_suffix)}" return job_id + args_list = shlex.split(command.strip()) logging.info(f"running command {command}") diff --git a/printer/server.py b/printer/server.py index 27be630..2ccf10a 100644 --- a/printer/server.py +++ b/printer/server.py @@ -6,6 +6,7 @@ import threading import time import uuid +import sqlite3 from fastapi import FastAPI, File, Form, HTTPException, UploadFile from fastapi.middleware.cors import CORSMiddleware @@ -63,6 +64,7 @@ def get_args() -> argparse.Namespace: default=False, help="specify if server should run in development. this means requests won't get sent to a printer but logger instead", ) + parser.add_argument( "--dont-delete-pdfs", action="store_true", @@ -119,6 +121,10 @@ def send_file_to_printer( # only the right printer works right now, so we default to it PRINTER_NAME = os.environ.get("RIGHT_PRINTER_NAME") + + if (args.development): + PRINTER_NAME = "HP_LaserJet_p2015dn_Right" + metrics_handler.print_jobs_recieved.inc() job_id = gerard.create_print_job( @@ -148,6 +154,17 @@ def api(): def metrics(): return prometheus_client.generate_latest() +@app.get("/status/") +async def status(id: str = ''): + try: + db = sqlite3.connect(args.database_file_path) + cursor = db.cursor() + cursor.execute(f"SELECT status FROM logs WHERE job_id = ?", (id,)) + status = cursor.fetchone()[0] + return {"status": status} + except Exception: + logging.exception("failed to get status of job with id: " + id) + return {"status": "failed"} @app.post("/print") async def read_item( diff --git a/printer/test/test_gerard.py b/printer/test/test_gerard.py index ddc4ed8..08e8053 100644 --- a/printer/test/test_gerard.py +++ b/printer/test/test_gerard.py @@ -41,6 +41,7 @@ def test_create_print_job(self, mock_popen): mock_popen.call_args_list[0], mock.call( shlex.split(gerard.LP_COMMAND.format( + hold_time="immediate", num_copies=1, maybe_page_range="1", sides="one-side", @@ -76,6 +77,7 @@ def test_create_print_job_nonzero_returncode(self, mock_popen): mock_popen.call_args_list[0], mock.call( shlex.split(gerard.LP_COMMAND.format( + hold_time="immediate", num_copies=1, maybe_page_range="", sides="dark-side", @@ -113,6 +115,7 @@ def test_create_print_job_cant_parse_stdout(self, mock_popen): mock_popen.call_args_list[0], mock.call( shlex.split(gerard.LP_COMMAND.format( + hold_time="immediate", num_copies=1, maybe_page_range="1", sides="one-side", @@ -129,19 +132,19 @@ def test_create_print_job_cant_parse_development_mode(self): self.assertEqual( gerard.create_print_job( - 1, "1", "one-side", "HP_P2015_DN", "/tmp/test-id", True + 1, "1", "one-side", "HP_P2015_DN", "/tmp/test-id", True, ), "HP_LaserJet_p2015dn_Right-0", ) self.assertEqual( gerard.create_print_job( - 1, "1", "one-side", "HP_P2015_DN", "/tmp/test-id", True + 1, "1", "one-side", "HP_P2015_DN", "/tmp/test-id", True, ), "HP_LaserJet_p2015dn_Right-1", ) self.assertEqual( gerard.create_print_job( - 1, "1", "one-side", "HP_P2015_DN", "/tmp/test-id", True + 1, "1", "one-side", "HP_P2015_DN", "/tmp/test-id", True, ), "HP_LaserJet_p2015dn_Right-2", ) diff --git a/printer/test/test_server.py b/printer/test/test_server.py index 54e278a..56acf3c 100644 --- a/printer/test/test_server.py +++ b/printer/test/test_server.py @@ -78,6 +78,7 @@ def test_print_endpoint(self, mock_pathlib_unlink, mock_open_func, mock_popen, _ mock_popen.call_args_list[0], mock.call( shlex.split(gerard.LP_COMMAND.format( + hold_time="immediate", num_copies=1, maybe_page_range="", sides="one-sided", @@ -137,6 +138,7 @@ def test_print_endpoint_dont_delete_pdf( mock_popen.call_args_list[0], mock.call( shlex.split(gerard.LP_COMMAND.format( + hold_time="immediate", num_copies=1, maybe_page_range="", sides="one-sided", @@ -221,6 +223,7 @@ def test_print_endpoint_nonzero_returncode( mock_popen.call_args_list[0], mock.call( shlex.split(gerard.LP_COMMAND.format( + hold_time="immediate", num_copies=1, maybe_page_range="", sides="dark-side", @@ -275,6 +278,7 @@ def test_junk_print_id(self, mock_pathlib_unlink, mock_open_func, mock_popen, _) mock_popen.call_args_list[0], mock.call( shlex.split(gerard.LP_COMMAND.format( + hold_time="immediate", num_copies=1, maybe_page_range="", sides="one-sided", diff --git a/printer/what_dev.sh b/printer/what_dev.sh new file mode 100644 index 0000000..4b0b4d4 --- /dev/null +++ b/printer/what_dev.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +# MAKE SURE THIS FILE IS USING LF FOR ITS EOL SEQUENCE!!!!!!!!!!! +# OTHERWISE DOCKER WILL COMPLAIN THAT THIS FILE DOESNT EXIST!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +/root/start-cups.sh > /dev/null 2>&1 & + +sleep 10 + +lpadmin -p HP_LaserJet_p2015dn_Right -E -v file:///dev/null + +python3 /app/printer/server.py $@