openlp/openlp/core/api/http/server.py

188 lines
7.5 KiB
Python
Raw Normal View History

2016-06-04 10:50:43 +00:00
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
2019-04-13 13:00:22 +00:00
##########################################################################
# OpenLP - Open Source Lyrics Projection #
# ---------------------------------------------------------------------- #
# Copyright (c) 2008-2019 OpenLP Developers #
# ---------------------------------------------------------------------- #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
##########################################################################
"""
2016-06-05 21:16:13 +00:00
The :mod:`http` module contains the API web server. This is a lightweight web server used by remotes to interact
with OpenLP. It uses JSON to communicate with the remotes.
"""
2016-06-05 16:20:39 +00:00
import logging
2017-09-26 21:18:09 +00:00
import time
2017-09-26 21:18:09 +00:00
from PyQt5 import QtCore, QtWidgets
from waitress.server import create_server
2017-09-26 21:18:09 +00:00
from openlp.core.api.deploy import download_and_check, download_sha256
2018-10-02 04:39:42 +00:00
from openlp.core.api.endpoint.controller import api_controller_endpoint, controller_endpoint
from openlp.core.api.endpoint.core import blank_endpoint, chords_endpoint, main_endpoint, stage_endpoint
2017-09-26 21:04:39 +00:00
from openlp.core.api.endpoint.remote import remote_endpoint
2018-10-02 04:39:42 +00:00
from openlp.core.api.endpoint.service import api_service_endpoint, service_endpoint
from openlp.core.api.http import application, register_endpoint
2017-10-07 07:05:07 +00:00
from openlp.core.api.poll import Poller
from openlp.core.common.applocation import AppLocation
2018-10-02 04:39:42 +00:00
from openlp.core.common.i18n import UiStrings, translate
2017-10-23 22:09:57 +00:00
from openlp.core.common.mixins import LogMixin, RegistryProperties
2017-10-07 07:05:07 +00:00
from openlp.core.common.path import create_paths
2017-10-23 22:09:57 +00:00
from openlp.core.common.registry import Registry, RegistryBase
2017-10-07 07:05:07 +00:00
from openlp.core.common.settings import Settings
from openlp.core.threading import ThreadWorker, run_thread
2018-10-02 04:39:42 +00:00
2016-06-05 16:20:39 +00:00
log = logging.getLogger(__name__)
2016-06-04 10:50:43 +00:00
class HttpWorker(ThreadWorker):
"""
2016-06-05 21:16:13 +00:00
A special Qt thread class to allow the HTTP server to run at the same time as the UI.
"""
def start(self):
2016-06-04 10:50:43 +00:00
"""
2016-06-05 21:16:13 +00:00
Run the thread.
"""
2016-07-09 11:21:25 +00:00
address = Settings().value('api/ip address')
port = Settings().value('api/port')
2017-09-27 18:56:21 +00:00
Registry().execute('get_website_version')
try:
self.server = create_server(application, host=address, port=port)
self.server.run()
except OSError:
log.exception('An error occurred when serving the application.')
self.quit.emit()
def stop(self):
"""
A method to stop the worker
"""
if hasattr(self, 'server'):
2018-01-06 07:02:45 +00:00
# Loop through all the channels and close them to stop the server
for channel in self.server._map.values():
if hasattr(channel, 'close'):
channel.close()
2017-10-23 22:09:57 +00:00
class HttpServer(RegistryBase, RegistryProperties, LogMixin):
"""
2016-06-05 21:16:13 +00:00
Wrapper round a server instance
"""
2016-08-13 05:18:46 +00:00
def __init__(self, parent=None):
"""
2016-06-13 19:51:46 +00:00
Initialise the http server, and start the http server
"""
2016-08-13 05:18:46 +00:00
super(HttpServer, self).__init__(parent)
if not Registry().get_flag('no_web_server'):
worker = HttpWorker()
run_thread(worker, 'http_server')
2017-12-02 09:11:22 +00:00
Registry().register_function('download_website', self.first_time)
Registry().register_function('get_website_version', self.website_version)
2017-09-29 18:53:04 +00:00
Registry().set_flag('website_version', '0.0')
2016-08-13 05:18:46 +00:00
def bootstrap_post_set_up(self):
"""
Register the poll return service and start the servers.
"""
2017-09-26 21:18:09 +00:00
self.initialise()
2016-08-13 05:18:46 +00:00
self.poller = Poller()
Registry().register('poller', self.poller)
2016-12-17 06:58:44 +00:00
application.initialise()
2016-08-13 05:18:46 +00:00
register_endpoint(controller_endpoint)
register_endpoint(api_controller_endpoint)
2017-06-18 05:21:23 +00:00
register_endpoint(chords_endpoint)
2016-08-13 05:18:46 +00:00
register_endpoint(stage_endpoint)
register_endpoint(blank_endpoint)
register_endpoint(main_endpoint)
register_endpoint(service_endpoint)
register_endpoint(api_service_endpoint)
2017-09-26 21:04:39 +00:00
register_endpoint(remote_endpoint)
2017-09-26 21:18:09 +00:00
@staticmethod
def initialise():
"""
Create the internal file structure if it does not exist
:return:
"""
2017-10-07 07:05:07 +00:00
create_paths(AppLocation.get_section_data_path('remotes') / 'assets',
AppLocation.get_section_data_path('remotes') / 'images',
AppLocation.get_section_data_path('remotes') / 'static',
AppLocation.get_section_data_path('remotes') / 'static' / 'index',
AppLocation.get_section_data_path('remotes') / 'templates')
2017-09-26 21:18:09 +00:00
def first_time(self):
"""
Import web site code if active
"""
self.application.process_events()
2017-09-29 18:53:04 +00:00
progress = DownloadProgressDialog(self)
2017-09-26 21:18:09 +00:00
progress.forceShow()
self.application.process_events()
time.sleep(1)
download_and_check(progress)
self.application.process_events()
time.sleep(1)
progress.close()
self.application.process_events()
Settings().setValue('remotes/download version', self.version)
def website_version(self):
"""
Download and save the website version and sha256
:return: None
"""
sha256, self.version = download_sha256()
Registry().set_flag('website_sha256', sha256)
Registry().set_flag('website_version', self.version)
2017-09-29 18:53:04 +00:00
class DownloadProgressDialog(QtWidgets.QProgressDialog):
2017-09-26 21:18:09 +00:00
"""
Local class to handle download display based and supporting httputils:get_web_page
"""
def __init__(self, parent):
2017-09-29 18:53:04 +00:00
super(DownloadProgressDialog, self).__init__(parent.main_window)
2017-09-26 21:18:09 +00:00
self.parent = parent
self.setWindowModality(QtCore.Qt.WindowModal)
self.setWindowTitle(translate('RemotePlugin', 'Importing Website'))
self.setLabelText(UiStrings().StartingImport)
self.setCancelButton(None)
self.setRange(0, 1)
self.setMinimumDuration(0)
self.was_cancelled = False
self.previous_size = 0
2018-01-04 06:01:35 +00:00
def update_progress(self, count, block_size):
2017-09-26 21:18:09 +00:00
"""
Calculate and display the download progress.
"""
increment = (count * block_size) - self.previous_size
self._increment_progress_bar(None, increment)
self.previous_size = count * block_size
def _increment_progress_bar(self, status_text, increment=1):
"""
Update the wizard progress page.
:param status_text: Current status information to display.
:param increment: The value to increment the progress bar by.
"""
if status_text:
self.setText(status_text)
if increment > 0:
self.setValue(self.value() + increment)
2017-09-27 19:21:08 +00:00
self.parent.application.process_events()