This repository has been archived by the owner on Oct 5, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
odf2pdf.py
118 lines (105 loc) · 4.52 KB
/
odf2pdf.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import atexit
import contextlib
import logging
import os
import tempfile
from datetime import datetime
from flask import Flask, jsonify, make_response, request, send_file
from libreoffice import LibreOffice
from nocache import nocache
from requestid import requestid, RequestIdFilter
VALID_MIME_TYPES = {
'application/vnd.oasis.opendocument.text': 'odt',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
# Leaving this all here for future support
# 'application/vnd.oasis.opendocument.text-template': 'ott',
# 'application/vnd.oasis.opendocument.text-web': 'oth',
# 'application/vnd.oasis.opendocument.text-master': 'odm',
# 'application/vnd.oasis.opendocument.graphics': 'odg',
# 'application/vnd.oasis.opendocument.graphics-template':'otg',
# 'application/vnd.oasis.opendocument.presentation': 'odp',
# 'application/vnd.oasis.opendocument.presentation-template': 'otp',
# 'application/vnd.oasis.opendocument.spreadsheet': 'ods',
# 'application/vnd.oasis.opendocument.spreadsheet-template': 'ots',
# 'application/vnd.oasis.opendocument.chart': 'odc',
# 'application/vnd.oasis.opendocument.formula': 'odf',
# 'application/vnd.oasis.opendocument.database': 'odb',
# 'application/vnd.oasis.opendocument.image': 'odi',
# 'application/vnd.openofficeorg.extension': 'oxt'
}
# Application configuration
REQUEST_CHUNK_SIZE = int(os.environ.get('ODF2PDF_REQUEST_CHUNK_SIZE', 40960))
LOG_LEVEL = os.environ.get('ODF2PDF_LOG_LEVEL', 'INFO')
# Instantiating application
app = Flask(__name__)
# Configuring logger
logging.basicConfig(level=logging._nameToLevel[LOG_LEVEL],
format='%(asctime)s %(name)s [%(levelname)s] %(request_id)s "%(message)s"')
for handler in logging.root.handlers:
handler.addFilter(RequestIdFilter())
logger = logging.getLogger(__name__)
# Bootstrapping
logger = app.logger
logger.info("Booting up odf2pdf converter")
logger.info("Request chunk size is %d bytes" % REQUEST_CHUNK_SIZE)
logger.info("Default log level is %s" % LOG_LEVEL)
logger.debug("Debug mode is enabled")
backend = LibreOffice()
logger.info("odf2pdf converter ready to process requests")
@app.route('/api/v1/pdf', methods = ['POST'])
@nocache
@requestid
def convert_pdf():
start_time = datetime.now()
content_type = request.headers.get('Content-type')
if content_type not in VALID_MIME_TYPES:
error = "%s: format not supported" % content_type
logger.error(error)
return make_response(jsonify({'error': error}), 415)
else:
suffix = VALID_MIME_TYPES[content_type]
content_length = int(request.headers.get('Content-length'))
if content_length == 0:
error = "request data has zero length"
logger.error(error)
return make_response(jsonify({'error': error}), 411)
# Receiving the temporary file
logger.debug("Received request for content %s of size %d. Suffix is %s" % (content_type, content_length, suffix))
with tempfile.NamedTemporaryFile(suffix='.' + suffix, delete=False) as tmp:
# Saving request to file
saved = 0
while True:
logger.debug("Saved %d of %d" % (saved, content_length))
chunk = request.stream.read(REQUEST_CHUNK_SIZE)
saved += len(chunk)
if len(chunk) == 0:
break
tmp.write(chunk)
logger.debug("Content written to %s" % tmp.name)
# Files need to be closed but not deleted (heh) to be converted.
tmp.close()
res = tmp.name.replace("." + suffix, ".pdf")
logger.debug("Converting %s to %s" % (tmp.name, res))
try:
backend.convertFile(suffix, "pdf", tmp.name)
logger.debug("Sending file %s back to caller" % res)
delta = datetime.now() - start_time
logger.info("Converted %s with %d bytes in %d ms" % (content_type, content_length, delta.microseconds / 1000))
return send_file(res)
except Exception as e:
error = str(e)
logger.error(error)
return make_response(jsonify({'error': error}), 500)
finally:
with contextlib.suppress(FileNotFoundError):
logger.debug("Removing temp file %s", tmp.name)
os.remove(tmp.name)
logger.debug("Removing temp PDF file %s", res)
os.remove(res)
@atexit.register
def cleanup():
logger.info("Shutting down odf2pdf converter")
backend.shutdown()
if __name__ == '__main__':
# app.run(debug = True, port = 4000)
app.run(port = 4000)