diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..685450e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +venv +.idea +__pycache__ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6d8bc68 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,43 @@ +# STEP 1: build pdfact +FROM ubuntu:20.04 + +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update -y && apt-get upgrade -y && apt-get install -y maven git + +WORKDIR / +# TODO freeze revision? +RUN git clone https://github.com/ad-freiburg/pdfact.git +WORKDIR pdfact + +RUN mvn install -DskipTests + +# STEP 2: run service +FROM alpine:latest +WORKDIR / + +# copy build artifact +COPY --from=0 /pdfact/bin/pdfact.jar pdfact.jar + +# get java +RUN apk update \ + && apk upgrade \ + && apk add --no-cache openjdk11-jre +ENV JAVA_HOME="/usr/lib/jvm/java-11-openjdk" + +# get python +RUN apk add --no-cache python3 \ + && python3 -m ensurepip \ + && pip3 install --upgrade pip setuptools + +# set environment variables +ENV PYTHONDONTWRITEBYTECODE 1 +ENV PYTHONUNBUFFERED 1 + +# install flask app +WORKDIR /app +COPY ./requirements.txt . +RUN pip install -r requirements.txt + +COPY app.py gunicorn_conf.py ./ + +ENTRYPOINT ["gunicorn", "--conf", "gunicorn_conf.py", "--bind", "0.0.0.0:80", "app:app"] diff --git a/app.py b/app.py new file mode 100644 index 0000000..197f3fa --- /dev/null +++ b/app.py @@ -0,0 +1,56 @@ +from flask import Flask, request, flash, Response +from werkzeug.utils import secure_filename +import logging +from os import path, remove +import tempfile +import subprocess as sp + +app = Flask(__name__) + + +def get_format(req, fallback=("application/json", "json")): + accept = req.headers.get("accept").lower() + if accept == "application/json": + return accept, "json" + elif accept == "application/xml": + return accept, "xml" + elif accept == "text/plain": + return accept, "txt" + else: + return fallback + + +@app.route('/analyze', methods=["POST"]) +def analyze(): + if "file" not in request.files or len(request.files["file"].filename) == 0: + flash("No file.") + return + + # save file to tmp folder + file = request.files["file"] + file_path = path.join(tempfile.gettempdir(), secure_filename(file.filename)) + app.logger.debug(f"saving file as {file_path}") + file.save(file_path) + + + + mime, response_format = get_format(request) + cmd = ["java", "-jar", "/pdfact.jar", file_path, "--format", response_format] + app.logger.debug(f"running {' '.join(cmd)}") + + try: + result = sp.check_output(cmd) + return Response(result, mimetype=mime) + except sp.CalledProcessError: + return "Something went wrong", 500 + finally: + remove(file_path) + +if __name__ == '__main__': + app.run() +else: + # use gunicorns loglevel + gunicorn_logger = logging.getLogger("gunicorn.error") + app.logger.handlers = gunicorn_logger.handlers + app.logger.setLevel(gunicorn_logger.level) + app.logger.warn(gunicorn_logger.level) diff --git a/gunicorn_conf.py b/gunicorn_conf.py new file mode 100644 index 0000000..795268c --- /dev/null +++ b/gunicorn_conf.py @@ -0,0 +1,8 @@ +loglevel = "info" +errorlog = "-" # stderr +accesslog = "-" # stdout +worker_tmp_dir = "/dev/shm" +graceful_timeout = 120 +timeout = 120 +keepalive = 5 +threads = 4 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..bd753fb --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +Flask==2.2.2 +gunicorn==20.1.0 \ No newline at end of file