diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..60e20b7 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +.idea +.git +backend/transcode +backend/__pycache__ +backend/MiskaRisa264 +frontend/ang_dvrip/.angular +frontend/ang_dvrip/dist +frontend/ang_dvrip/node_modules \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c3488d8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,56 @@ +FROM ubuntu:22.04 + +RUN dpkg --add-architecture i386 \ + && apt-get update \ + && apt-get install -y ffmpeg wget unzip python3 python3-pip git curl \ + && mkdir -pm755 /etc/apt/keyrings \ + && wget -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key \ + && wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/jammy/winehq-jammy.sources \ + && apt-get update && apt-get install -y winehq-stable \ + && rm -rf /var/lib/apt/lists/* + +RUN curl -s https://deb.nodesource.com/setup_18.x | bash \ + && apt-get update && apt-get install -y nodejs \ + && rm -rf /var/lib/apt/lists/* + +RUN apt-get update && apt-get install -y nginx \ + && rm -rf /var/lib/apt/lists/* + +RUN mkdir /opt/win32-python && cd /opt/win32-python \ + && wget https://www.python.org/ftp/python/3.12.3/python-3.12.3-embed-win32.zip \ + && unzip python-3.12.3-embed-win32.zip \ + && rm python-3.12.3-embed-win32.zip + +RUN echo "wine test open python" \ + && cd /opt/win32-python \ + && wine python.exe --version + +#install backend dependes +RUN python3 -m pip config --user set global.index https://nexus.pblr-nyk.pro/repository/pypi-all/pypi && \ + python3 -m pip config --user set global.index-url https://nexus.pblr-nyk.pro/repository/pypi-all/simple && \ + python3 -m pip config --user set global.trusted-host nexus.pblr-nyk.pro +RUN python3 -m pip install fastapi aiofiles uvicorn git+https://github.com/OpenIPC/python-dvr + +RUN mkdir /app +WORKDIR /app + +#setup backend +COPY backend /app/backend +RUN cd backend && git clone https://git.pblr-nyk.pro/gsd/MiskaRisa264 && mv /opt/win32-python /app/backend/MiskaRisa264/python-win32 && echo "{}" >> config.json +RUN cd backend && python3 config_parser.py --no-hide-check --err-check + +#setup frontend +COPY frontend /app/frontend +RUN cd frontend/ang_dvrip \ + && npm install --reg https://nexus.pblr-nyk.pro/repository/npm/ \ + && npm run ng build \ + && rm -r /var/www/html \ + && mv dist/ang_dvrip /var/www/html + +RUN rm /etc/nginx/sites-available/default +COPY nginx.conf /etc/nginx/sites-available/default + +COPY entrypoint.sh / +EXPOSE 80 +ENV PYTHONUNBUFFERED 1 +ENTRYPOINT [ "/entrypoint.sh" ] \ No newline at end of file diff --git a/backend/config_parser.py b/backend/config_parser.py index f62cd72..42d8c87 100644 --- a/backend/config_parser.py +++ b/backend/config_parser.py @@ -1,7 +1,5 @@ -from genericpath import exists import os, sys from json import loads -from turtle import width import uuid from asyncio_dvrip import DVRIPCam import asyncio @@ -60,6 +58,7 @@ class TranscodeStatus: self.outFile = None self.done = False self.outSize = 0 + self.error = "" @property def outName(self): @@ -139,8 +138,11 @@ class TranscodeTools: def check_converter(self): from subprocess import call, DEVNULL + cmd = f"{self.python_win32} {self.converter_script} --help" + if platform.system() == "Linux": + cmd = "wine " + cmd try: - return not call(f"{self.python_win32} {self.converter_script} --help".split(), stdin=DEVNULL if self.hide_checks else None, stdout=DEVNULL if self.hide_checks else None, stderr=DEVNULL if self.hide_checks else None) + return not call(cmd.split(), stdin=DEVNULL if self.hide_checks else None, stdout=DEVNULL if self.hide_checks else None, stderr=DEVNULL if self.hide_checks else None) except: return False @@ -152,6 +154,7 @@ class TranscodeTools: elif platform.system() == "Linux": exec_cmd = "wine" exec_string.append(self.python_win32) + else: raise Exception("Unknown platform to transcode") exec_string.append(self.converter_script) @@ -184,6 +187,12 @@ class TranscodeTools: def deleteFile(self, source_file): os.remove(source_file) + async def processing_safe(self, status: TranscodeStatus, file:File, nvr: NVR, reCreate:bool = False): + try: + await self.processing(status, file, nvr, reCreate) + except Exception as e: + self.statuses[status.b64].error = str(e) + async def processing(self, status: TranscodeStatus, file:File, nvr: NVR, reCreate:bool = False): raw_file = os.path.join(self.transcode_directory, status.uuid + ".h264") @@ -234,7 +243,7 @@ class TranscodeTools: class Config: def __init__(self, config_name = "config.json", args = None) -> None: - raw = load_config(config_name) + raw = load_config(config_name) if args == None or not args.err_check else {} self.listen_address = raw.get("backend", {}).get("address", "0.0.0.0") self.listen_port = int(raw.get("backend", {}).get("port", "8080")) self.recorders = [] @@ -267,9 +276,13 @@ if __name__ == "__main__": import argparse parser = argparse.ArgumentParser() parser.add_argument("--no-hide-check", action="store_true") + parser.add_argument("--err-check", action="store_true") parser.add_argument("--test-h264toavi", type=str) args = parser.parse_args() config = Config(args = args) + if args.err_check: + sys.exit(0 if config.transcode_tools.enabled else 1) + if args.test_h264toavi: config.transcode_tools.h264toavi_test(args.test_h264toavi) sys.exit(0) diff --git a/backend/server.py b/backend/server.py index 9025fa9..7139ec6 100644 --- a/backend/server.py +++ b/backend/server.py @@ -119,7 +119,7 @@ class Server: file: File = File.from_b64(b64 + "==") self.config.transcode_tools.statuses[b64] = TranscodeStatus(b64) - background_tasks.add_task(self.config.transcode_tools.processing, status = self.config.transcode_tools.statuses[b64], file = file, nvr = nvr) + background_tasks.add_task(self.config.transcode_tools.processing_safe, status = self.config.transcode_tools.statuses[b64], file = file, nvr = nvr) return {"ok":True, "data":self.config.transcode_tools.statuses[b64]} except Exception as e: traceback.print_exc() diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..db09217 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,8 @@ +services: + dvrip_os: + build: ./ + ports: + - 4444:80 + volumes: + - ./backend/transcode/:/app/backend/transcode + - ./backend/config.json:/app/backend/config.json:ro \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..33d318e --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,3 @@ +#!/bin/bash +nginx \ +& cd /app/backend && python3 server.py \ No newline at end of file diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..f6e96a5 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,28 @@ +server { + listen 80 default_server; + listen [::]:80 default_server; + + root /var/www/html; + + index index.html index.htm index.nginx-debian.html; + + server_name _; + + location / { + try_files $uri $uri/ =404; + } + + location ^~ /api { + proxy_pass http://localhost:8080; + proxy_redirect off; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + add_header 'Access-Control-Allow-Origin' '*' always; + # kill cache + add_header Last-Modified $date_gmt; + add_header Cache-Control 'no-store, no-cache'; + if_modified_since off; + expires off; + etag off; + } +} \ No newline at end of file