From 0a6c338f3fb637c8d04a72aed92e809f61f9c2d2 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 8 Apr 2018 21:41:46 +0300 Subject: [PATCH] Feat(web): Do not allow to run two instances of `ml-web.py` The second instance redirects browser to the first one and exits. --- docs-ru/news.rst | 4 ++++ docs/news.rst | 3 +++ m_librarian/web/utils.py | 43 +++++++++++++++++++++++++++++++++++++++- scripts/ml-web.py | 13 ++++++++---- tmp/.gitignore | 2 ++ 5 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 tmp/.gitignore diff --git a/docs-ru/news.rst b/docs-ru/news.rst index 19b1ad4..3d0e16d 100644 --- a/docs-ru/news.rst +++ b/docs-ru/news.rst @@ -7,5 +7,9 @@ Version 0.1.0 (2018-04-08) * Web-интерфейс для поиска авторов, показа списка книг автора, загрузки одной книги. +* Программа `ml-web.py` не позволяет запускать два экземпляра. + Второй экземпляр перенаправляет web-обозреватель на web-интерфейс + первого экземпляра и прекращает работу. + * Опция `--download-to` в скрипте `ml-search.py` задаёт директорию для сохранения книг. diff --git a/docs/news.rst b/docs/news.rst index 80498f1..6042e69 100644 --- a/docs/news.rst +++ b/docs/news.rst @@ -7,6 +7,9 @@ Version 0.1.0 (2018-04-08) * Web-interface: Search for authors, list books by an author, download a book. +* Do not allow to run two instances of `ml-web.py` web-interfaces. + The second instance redirects browser to the first one and exits. + * Option `--download-to` provides the path to the download directory in script `ml-search.py`. diff --git a/m_librarian/web/utils.py b/m_librarian/web/utils.py index 2efe724..12be81f 100644 --- a/m_librarian/web/utils.py +++ b/m_librarian/web/utils.py @@ -1,7 +1,48 @@ +from fcntl import flock, LOCK_EX, LOCK_UN, LOCK_NB +from os import path, remove +import socket + + +lock_fname = path.join( + path.dirname(path.dirname(path.dirname(__file__))), + 'tmp', 'm_librarian.lock') + + +def get_lock(port): + try: + lock_file = open(lock_fname, 'r') + except IOError: # no lock file + pass + else: + try: + flock(lock_file, LOCK_EX | LOCK_NB) + except IOError: # locked + port = int(lock_file.readline()) + lock_file.close() + return None, port + else: + flock(lock_file, LOCK_UN) + lock_file.close() + + lock_file = open(lock_fname, 'w') + lock_file.write(str(port)) + lock_file.close() + lock_file = open(lock_fname, 'r') + flock(lock_file, LOCK_EX | LOCK_NB) + return lock_file, None + + +def close_lock(lock_file): + flock(lock_file, LOCK_UN) + lock_file.close() + lock_file = open(lock_fname, 'w') + lock_file.write('') + lock_file.close() + remove(lock_fname) + def get_open_port(): # https://stackoverflow.com/a/2838309/7976758 - import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(("", 0)) # s.listen(1) diff --git a/scripts/ml-web.py b/scripts/ml-web.py index bccac81..0387bc6 100755 --- a/scripts/ml-web.py +++ b/scripts/ml-web.py @@ -9,7 +9,7 @@ from bottle import thread # portable import from m_librarian.db import open_db import m_librarian.web.app # noqa: F401 imported but unused from m_librarian.web.server import run_server -from m_librarian.web.utils import get_open_port +from m_librarian.web.utils import get_lock, close_lock, get_open_port def start_browser(port): @@ -27,6 +27,11 @@ if __name__ == '__main__': else: port = get_open_port() - open_db() - thread.start_new_thread(start_browser, (port,)) - run_server(port=port) + lock_file, old_port = get_lock(port) + if lock_file: + open_db() + thread.start_new_thread(start_browser, (port,)) + run_server(port=port) + close_lock(lock_file) + else: # Another instance of the program is being run at a different port + start_browser(old_port) diff --git a/tmp/.gitignore b/tmp/.gitignore new file mode 100644 index 0000000..120f485 --- /dev/null +++ b/tmp/.gitignore @@ -0,0 +1,2 @@ +* +!/.gitignore -- 2.39.5