print with a random code
This commit is contained in:
parent
2e395edfd1
commit
ad2051e0e0
4 changed files with 79 additions and 18 deletions
|
@ -21,6 +21,8 @@ Now you can **point your browser to [http://localhost:7777/](http://localhost:77
|
||||||
|
|
||||||
You can also **run the server in https**, putting in the *ssl* directory two files named *httprint_key.pem* and *httprint_cert.pem*
|
You can also **run the server in https**, putting in the *ssl* directory two files named *httprint_key.pem* and *httprint_cert.pem*
|
||||||
|
|
||||||
|
By default the **--print-with-code** argument is true, and the uploaded files are just scheduled for priting. To actually print them, you should supply the generated code, for example: `curl -X POST http://localhost:7777/api/print/1234`
|
||||||
|
|
||||||
|
|
||||||
# License and copyright
|
# License and copyright
|
||||||
|
|
||||||
|
|
4
dist/static/js/httprint.js
vendored
4
dist/static/js/httprint.js
vendored
|
@ -12,8 +12,10 @@ function uploadFile() {
|
||||||
if (reply && !reply.error) {
|
if (reply && !reply.error) {
|
||||||
iziToast.success({
|
iziToast.success({
|
||||||
title: "DONE!",
|
title: "DONE!",
|
||||||
message: "file sent to printer",
|
message: reply.message,
|
||||||
position: 'topCenter',
|
position: 'topCenter',
|
||||||
|
timeout: false,
|
||||||
|
closeOnEscape: true,
|
||||||
layout: 2
|
layout: 2
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
89
httprint.py
89
httprint.py
|
@ -16,9 +16,11 @@ limitations under the License.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import time
|
import time
|
||||||
|
import glob
|
||||||
import random
|
import random
|
||||||
import asyncio
|
import shutil
|
||||||
import logging
|
import logging
|
||||||
import subprocess
|
import subprocess
|
||||||
import multiprocessing as mp
|
import multiprocessing as mp
|
||||||
|
@ -32,10 +34,12 @@ from tornado import gen, escape
|
||||||
|
|
||||||
|
|
||||||
API_VERSION = '1.0'
|
API_VERSION = '1.0'
|
||||||
UPLOAD_PATH = 'uploads'
|
QUEUE_DIR = 'queue'
|
||||||
|
ARCHIVE = True
|
||||||
|
ARCHIVE_DIR = 'archive'
|
||||||
PRINT_CMD = ['lp']
|
PRINT_CMD = ['lp']
|
||||||
PROCESS_TIMEOUT = 60
|
CODE_DIGITS = 4
|
||||||
ENCODING = 'utf-8'
|
PRINT_WITH_CODE = True
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
logger.setLevel(logging.INFO)
|
logger.setLevel(logging.INFO)
|
||||||
|
@ -118,8 +122,51 @@ class BaseHandler(tornado.web.RequestHandler):
|
||||||
p = mp.Process(target=self._run, args=(cmd,))
|
p = mp.Process(target=self._run, args=(cmd,))
|
||||||
p.start()
|
p.start()
|
||||||
|
|
||||||
|
def print_file(self, fname):
|
||||||
|
cmd = PRINT_CMD + [fname]
|
||||||
|
self.run_subprocess(cmd)
|
||||||
|
if self.cfg.archive:
|
||||||
|
if not os.path.isdir(self.cfg.archive_dir):
|
||||||
|
os.makedirs(self.cfg.archive_dir)
|
||||||
|
shutil.move(fname, self.cfg.archive_dir)
|
||||||
|
|
||||||
|
|
||||||
|
class PrintHandler(BaseHandler):
|
||||||
|
"""File print handler."""
|
||||||
|
@gen.coroutine
|
||||||
|
def post(self, code=None):
|
||||||
|
if not code:
|
||||||
|
self.build_error("empty code")
|
||||||
|
return
|
||||||
|
files = glob.glob(self.cfg.queue_dir + '/%s-*' % code)
|
||||||
|
if not files:
|
||||||
|
self.build_error("no matching files")
|
||||||
|
return
|
||||||
|
self.print_file(files[0])
|
||||||
|
self.build_success("file sent to printer")
|
||||||
|
|
||||||
|
|
||||||
class UploadHandler(BaseHandler):
|
class UploadHandler(BaseHandler):
|
||||||
"""Reset schedules handler."""
|
"""File upload handler."""
|
||||||
|
def generateCode(self):
|
||||||
|
filler = '%0' + str(self.cfg.code_digits) + 'd'
|
||||||
|
existing = set()
|
||||||
|
re_code = re.compile('(\d{' + str(self.cfg.code_digits) + '})-.*')
|
||||||
|
for fname in glob.glob(self.cfg.queue_dir + '/*'):
|
||||||
|
fname = os.path.basename(fname)
|
||||||
|
match = re_code.match(fname)
|
||||||
|
if not match:
|
||||||
|
continue
|
||||||
|
fcode = match.group(1)
|
||||||
|
existing.add(fcode)
|
||||||
|
code = None
|
||||||
|
for i in range(10**self.cfg.code_digits):
|
||||||
|
intCode = random.randint(0, (10**self.cfg.code_digits)-1)
|
||||||
|
code = filler % intCode
|
||||||
|
if code not in existing:
|
||||||
|
break
|
||||||
|
return code
|
||||||
|
|
||||||
@gen.coroutine
|
@gen.coroutine
|
||||||
def post(self):
|
def post(self):
|
||||||
if not self.request.files.get('file'):
|
if not self.request.files.get('file'):
|
||||||
|
@ -132,13 +179,12 @@ class UploadHandler(BaseHandler):
|
||||||
extension = os.path.splitext(webFname)[1]
|
extension = os.path.splitext(webFname)[1]
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
if not os.path.isdir(UPLOAD_PATH):
|
if not os.path.isdir(self.cfg.queue_dir):
|
||||||
os.makedirs(UPLOAD_PATH)
|
os.makedirs(self.cfg.queue_dir)
|
||||||
fname = '%s-%s%s' % (
|
now = time.strftime('%Y%m%d%H%M%S')
|
||||||
time.strftime('%Y%m%d%H%M%S'),
|
code = self.generateCode()
|
||||||
'%04d' % random.randint(0, 9999),
|
fname = '%s-%s%s' % (code, now, extension)
|
||||||
extension)
|
pname = os.path.join(self.cfg.queue_dir, fname)
|
||||||
pname = os.path.join(UPLOAD_PATH, fname)
|
|
||||||
try:
|
try:
|
||||||
with open(pname, 'wb') as fd:
|
with open(pname, 'wb') as fd:
|
||||||
fd.write(fileinfo['body'])
|
fd.write(fileinfo['body'])
|
||||||
|
@ -147,11 +193,14 @@ class UploadHandler(BaseHandler):
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
with open(pname + '.info', 'w') as fd:
|
with open(pname + '.info', 'w') as fd:
|
||||||
fd.write('originale file name: %s\n' % webFname)
|
fd.write('original file name: %s\n' % webFname)
|
||||||
|
fd.write('uploaded on: %s\n' % now)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
cmd = PRINT_CMD + [pname]
|
if self.cfg.print_with_code:
|
||||||
self.run_subprocess(cmd)
|
self.build_success("go to the printer and enter this code: %s" % code)
|
||||||
|
else:
|
||||||
|
self.print_file(pname)
|
||||||
self.build_success("file sent to printer")
|
self.build_success("file sent to printer")
|
||||||
|
|
||||||
|
|
||||||
|
@ -175,6 +224,11 @@ def serve():
|
||||||
help='specify the SSL certificate to use for secure connections')
|
help='specify the SSL certificate to use for secure connections')
|
||||||
define('ssl_key', default=os.path.join(os.path.dirname(__file__), 'ssl', 'httprint_key.pem'),
|
define('ssl_key', default=os.path.join(os.path.dirname(__file__), 'ssl', 'httprint_key.pem'),
|
||||||
help='specify the SSL private key to use for secure connections')
|
help='specify the SSL private key to use for secure connections')
|
||||||
|
define('code-digits', default=CODE_DIGITS, help='number of digits of the code', type=int)
|
||||||
|
define('queue-dir', default=QUEUE_DIR, help='directory to store files before they are printed', type=str)
|
||||||
|
define('archive', default=True, help='archive printed files', type=bool)
|
||||||
|
define('archive-dir', default=ARCHIVE_DIR, help='directory to archive printed files', type=str)
|
||||||
|
define('print-with-code', default=True, help='a code must be entered for printing', type=bool)
|
||||||
define('debug', default=False, help='run in debug mode', type=bool)
|
define('debug', default=False, help='run in debug mode', type=bool)
|
||||||
tornado.options.parse_command_line()
|
tornado.options.parse_command_line()
|
||||||
|
|
||||||
|
@ -185,12 +239,15 @@ def serve():
|
||||||
if os.path.isfile(options.ssl_key) and os.path.isfile(options.ssl_cert):
|
if os.path.isfile(options.ssl_key) and os.path.isfile(options.ssl_cert):
|
||||||
ssl_options = dict(certfile=options.ssl_cert, keyfile=options.ssl_key)
|
ssl_options = dict(certfile=options.ssl_cert, keyfile=options.ssl_key)
|
||||||
|
|
||||||
init_params = dict(listen_port=options.port, logger=logger, ssl_options=ssl_options)
|
init_params = dict(listen_port=options.port, logger=logger, ssl_options=ssl_options, cfg=options)
|
||||||
|
|
||||||
_upload_path = r'upload/?'
|
_upload_path = r'upload/?'
|
||||||
|
_print_path = r'print/(?P<code>\d+)'
|
||||||
application = tornado.web.Application([
|
application = tornado.web.Application([
|
||||||
(r'/api/%s' % _upload_path, UploadHandler, init_params),
|
(r'/api/%s' % _upload_path, UploadHandler, init_params),
|
||||||
(r'/api/v%s/%s' % (API_VERSION, _upload_path), UploadHandler, init_params),
|
(r'/api/v%s/%s' % (API_VERSION, _upload_path), UploadHandler, init_params),
|
||||||
|
(r'/api/%s' % _print_path, PrintHandler, init_params),
|
||||||
|
(r'/api/v%s/%s' % (API_VERSION, _print_path), PrintHandler, init_params),
|
||||||
(r'/?(.*)', TemplateHandler, init_params),
|
(r'/?(.*)', TemplateHandler, init_params),
|
||||||
],
|
],
|
||||||
static_path=os.path.join(os.path.dirname(__file__), 'dist/static'),
|
static_path=os.path.join(os.path.dirname(__file__), 'dist/static'),
|
||||||
|
|
Loading…
Reference in a new issue