forked from openlp/openlp
Move Websockets to core from plugin
This commit is contained in:
parent
055280860c
commit
8ce073d83f
39
openlp/core/lib/remote/__init__.py
Normal file
39
openlp/core/lib/remote/__init__.py
Normal file
@ -0,0 +1,39 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2016 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; version 2 of the License. #
|
||||
# #
|
||||
# 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, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
import os
|
||||
from openlp.core.common import AppLocation
|
||||
from .poll import OpenLPPoll
|
||||
from .wsserver import OpenWSServer
|
||||
from .remotecontroller import RemoteController
|
||||
|
||||
|
||||
def get_cert_file(file_type):
|
||||
"""
|
||||
Helper method to get certificate files
|
||||
:param file_type: file suffix key, cert or pem
|
||||
:return: full path to file
|
||||
"""
|
||||
local_data = AppLocation.get_directory(AppLocation.DataDir)
|
||||
return os.path.join(local_data, 'remotes', 'openlp.{type}'.format(type=file_type))
|
||||
|
||||
__all__ = ['OpenLPPoll', 'RemoteController', 'get_cert_file']
|
53
openlp/core/lib/remote/remotecontroller.py
Normal file
53
openlp/core/lib/remote/remotecontroller.py
Normal file
@ -0,0 +1,53 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2016 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; version 2 of the License. #
|
||||
# #
|
||||
# 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, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
from openlp.core.common import OpenLPMixin, Registry, RegistryMixin, RegistryProperties
|
||||
from openlp.core.lib.remote import OpenWSServer
|
||||
|
||||
|
||||
class RemoteController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
||||
"""
|
||||
The implementation of the Media Controller. The Media Controller adds an own class for every Player.
|
||||
Currently these are QtWebkit, Phonon and Vlc. display_controllers are an array of controllers keyed on the
|
||||
slidecontroller or plugin which built them.
|
||||
|
||||
ControllerType is the class containing the key values.
|
||||
|
||||
media_players are an array of media players keyed on player name.
|
||||
|
||||
current_media_players is an array of player instances keyed on ControllerType.
|
||||
|
||||
"""
|
||||
def __init__(self, parent=None):
|
||||
"""
|
||||
Constructor
|
||||
"""
|
||||
super(RemoteController, self).__init__(parent)
|
||||
self.media_players = {}
|
||||
self.display_controllers = {}
|
||||
self.current_media_players = {}
|
||||
# Registry().register_function('playbackPlay', self.media_play_msg)
|
||||
|
||||
def bootstrap_post_set_up(self):
|
||||
"""
|
||||
process the bootstrap post setup request
|
||||
"""
|
||||
self.wsserver = OpenWSServer()
|
149
openlp/core/lib/remote/wsserver.py
Normal file
149
openlp/core/lib/remote/wsserver.py
Normal file
@ -0,0 +1,149 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2016 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; version 2 of the License. #
|
||||
# #
|
||||
# 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, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import websockets
|
||||
import logging
|
||||
import time
|
||||
|
||||
from PyQt5 import QtCore
|
||||
|
||||
from openlp.core.common import Settings, RegistryProperties, OpenLPMixin
|
||||
from openlp.core.lib.remote import OpenLPPoll
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HttpThread(QtCore.QThread):
|
||||
"""
|
||||
A special Qt thread class to allow the HTTP server to run at the same time as the UI.
|
||||
"""
|
||||
def __init__(self, server):
|
||||
"""
|
||||
Constructor for the thread class.
|
||||
|
||||
:param server: The http server class.
|
||||
"""
|
||||
super(HttpThread, self).__init__(None)
|
||||
self.http_server = server
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
Run the thread.
|
||||
"""
|
||||
self.http_server.start_server()
|
||||
|
||||
def stop(self):
|
||||
self.http_server.stop = True
|
||||
|
||||
|
||||
class OpenWSServer(RegistryProperties, OpenLPMixin):
|
||||
"""
|
||||
Wrapper round a server instance
|
||||
"""
|
||||
def __init__(self, secure=False):
|
||||
"""
|
||||
Initialise the http server, and start the server of the correct type http / https
|
||||
"""
|
||||
super(OpenWSServer, self).__init__()
|
||||
self.settings_section = 'remotes'
|
||||
self.secure = secure
|
||||
self.http_thread = HttpThread(self)
|
||||
self.http_thread.start()
|
||||
|
||||
def start_server(self):
|
||||
"""
|
||||
Start the correct server and save the handler
|
||||
"""
|
||||
address = Settings().value(self.settings_section + '/ip address')
|
||||
is_secure = Settings().value(self.settings_section + '/https enabled')
|
||||
port = '4318'
|
||||
self.start_websocket_instance(address, port)
|
||||
# If web socket server start listening
|
||||
if hasattr(self, 'ws_server') and self.ws_server:
|
||||
event_loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(event_loop)
|
||||
event_loop.run_until_complete(self.ws_server)
|
||||
event_loop.run_forever()
|
||||
else:
|
||||
log.debug('Failed to start ws server on port {port}'.format(port=port))
|
||||
|
||||
def start_websocket_instance(self, address, port):
|
||||
"""
|
||||
Start the server
|
||||
|
||||
:param address: The server address
|
||||
:param port: The run port
|
||||
"""
|
||||
loop = 1
|
||||
while loop < 4:
|
||||
try:
|
||||
self.ws_server = websockets.serve(self.handle_websocket, address, port)
|
||||
log.debug("Web Socket Server started for class {address} {port}".format(address=address, port=port))
|
||||
break
|
||||
except Exception as e:
|
||||
log.error('Failed to start ws server {why}'.format(why=e))
|
||||
loop += 1
|
||||
time.sleep(0.1)
|
||||
|
||||
@staticmethod
|
||||
async def handle_websocket(request, path):
|
||||
"""
|
||||
Handle web socket requests and return the poll information.
|
||||
Check ever 0.5 seconds to get the latest postion and send if changed.
|
||||
Only gets triggered when 1st client attaches
|
||||
:param request: request from client
|
||||
:param path: not used - future to register for a different end point
|
||||
:return:
|
||||
"""
|
||||
log.debug("web socket handler registered with client")
|
||||
previous_poll = None
|
||||
previous_main_poll = None
|
||||
if path == '/poll':
|
||||
while True:
|
||||
current_poll = OpenLPPoll().poll()
|
||||
if current_poll != previous_poll:
|
||||
await request.send(current_poll)
|
||||
previous_poll = current_poll
|
||||
await asyncio.sleep(0.2)
|
||||
elif path == '/main_poll':
|
||||
while True:
|
||||
main_poll = OpenLPPoll().main_poll()
|
||||
if main_poll != previous_main_poll:
|
||||
await request.send(main_poll)
|
||||
previous_main_poll = main_poll
|
||||
await asyncio.sleep(0.2)
|
||||
|
||||
def stop_server(self):
|
||||
"""
|
||||
Stop the server
|
||||
"""
|
||||
if self.http_thread.isRunning():
|
||||
self.http_thread.stop()
|
||||
self.httpd = None
|
||||
log.debug('Stopped the server.')
|
@ -40,13 +40,13 @@ from openlp.core.common.actions import ActionList, CategoryOrder
|
||||
from openlp.core.common.versionchecker import get_application_version
|
||||
from openlp.core.lib import Renderer, PluginManager, ImageManager, PluginStatus, ScreenList, build_icon
|
||||
from openlp.core.lib.ui import UiStrings, create_action
|
||||
from openlp.core.lib.remote import RemoteController
|
||||
from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, ThemeManager, LiveController, PluginForm, \
|
||||
ShortcutListForm, FormattingTagForm, PreviewController
|
||||
from openlp.core.ui.firsttimeform import FirstTimeForm
|
||||
from openlp.core.ui.media import MediaController
|
||||
from openlp.core.ui.printserviceform import PrintServiceForm
|
||||
from openlp.core.ui.projector.manager import ProjectorManager
|
||||
from openlp.core.ui.lib.toolbar import OpenLPToolbar
|
||||
from openlp.core.ui.lib.dockwidget import OpenLPDockWidget
|
||||
from openlp.core.ui.lib.mediadockmanager import MediaDockManager
|
||||
|
||||
@ -529,6 +529,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties):
|
||||
Settings().set_up_default_values()
|
||||
self.about_form = AboutForm(self)
|
||||
MediaController()
|
||||
RemoteController()
|
||||
SettingsForm(self)
|
||||
self.formatting_tag_form = FormattingTagForm(self)
|
||||
self.shortcut_form = ShortcutListForm(self)
|
||||
|
@ -38,7 +38,6 @@ from openlp.core.ui.media.mediaplayer import MediaPlayer
|
||||
from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players,\
|
||||
parse_optical_path
|
||||
from openlp.core.ui.lib.toolbar import OpenLPToolbar
|
||||
from openlp.core.ui.lib.dockwidget import OpenLPDockWidget
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -20,10 +20,8 @@
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
from .poll import OpenLPPoll
|
||||
from .remotetab import RemoteTab
|
||||
from .httprouter import HttpRouter
|
||||
from .httpserver import OpenLPServer
|
||||
from .remotetab import RemoteTab
|
||||
|
||||
|
||||
__all__ = ['RemoteTab', 'OpenLPServer', 'HttpRouter', 'OpenLPPoll']
|
||||
__all__ = ['RemoteTab', 'OpenLPServer', 'HttpRouter']
|
||||
|
@ -25,19 +25,17 @@ The :mod:`http` module contains the API web server. This is a lightweight web se
|
||||
with OpenLP. It uses JSON to communicate with the remotes.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import ssl
|
||||
import socket
|
||||
import websockets
|
||||
import os
|
||||
import logging
|
||||
import time
|
||||
|
||||
from PyQt5 import QtCore
|
||||
|
||||
from openlp.core.common import AppLocation, Settings, RegistryProperties, OpenLPMixin
|
||||
from openlp.core.common import Settings, RegistryProperties, OpenLPMixin
|
||||
|
||||
from openlp.plugins.remotes.lib import HttpRouter, OpenLPPoll
|
||||
from openlp.plugins.remotes.lib import HttpRouter
|
||||
from openlp.core.lib.remote import get_cert_file
|
||||
|
||||
from socketserver import BaseServer, ThreadingMixIn
|
||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
@ -97,14 +95,13 @@ class OpenLPServer(RegistryProperties, OpenLPMixin):
|
||||
"""
|
||||
Wrapper round a server instance
|
||||
"""
|
||||
def __init__(self, websocket=False, secure=False):
|
||||
def __init__(self, secure=False):
|
||||
"""
|
||||
Initialise the http server, and start the server of the correct type http / https
|
||||
"""
|
||||
super(OpenLPServer, self).__init__()
|
||||
self.settings_section = 'remotes'
|
||||
self.secure = secure
|
||||
self.websocket = websocket
|
||||
self.http_thread = HttpThread(self)
|
||||
self.http_thread.start()
|
||||
|
||||
@ -124,23 +121,12 @@ class OpenLPServer(RegistryProperties, OpenLPMixin):
|
||||
if self.secure:
|
||||
self.start_server_instance(address, port, HTTPSServer)
|
||||
else:
|
||||
if self.websocket:
|
||||
self.start_websocket_instance(address, port)
|
||||
else:
|
||||
self.start_server_instance(address, port, ThreadingHTTPServer)
|
||||
self.start_server_instance(address, port, ThreadingHTTPServer)
|
||||
# If HTTP server start listening
|
||||
if hasattr(self, 'httpd') and self.httpd:
|
||||
self.httpd.serve_forever()
|
||||
else:
|
||||
log.debug('Failed to start http server on port {port}'.format(port=port))
|
||||
# If web socket server start listening
|
||||
if hasattr(self, 'ws_server') and self.ws_server:
|
||||
event_loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(event_loop)
|
||||
event_loop.run_until_complete(self.ws_server)
|
||||
event_loop.run_forever()
|
||||
else:
|
||||
log.debug('Failed to start ws server on port {port}'.format(port=port))
|
||||
|
||||
def start_server_instance(self, address, port, server_class):
|
||||
"""
|
||||
@ -168,52 +154,6 @@ class OpenLPServer(RegistryProperties, OpenLPMixin):
|
||||
loop += 1
|
||||
time.sleep(0.1)
|
||||
|
||||
def start_websocket_instance(self, address, port):
|
||||
"""
|
||||
Start the server
|
||||
|
||||
:param address: The server address
|
||||
:param port: The run port
|
||||
"""
|
||||
loop = 1
|
||||
while loop < 4:
|
||||
try:
|
||||
self.ws_server = websockets.serve(self.handle_websocket, address, '4318')
|
||||
log.debug("Web Socket Server started for class {address} {port:d}".format(address=address, port=port))
|
||||
break
|
||||
except Exception as e:
|
||||
log.error('Failed to start ws server {why}'.format(why=e))
|
||||
loop += 1
|
||||
time.sleep(0.1)
|
||||
|
||||
@staticmethod
|
||||
async def handle_websocket(request, path):
|
||||
"""
|
||||
Handle web socket requests and return the poll information.
|
||||
Check ever 0.5 seconds to get the latest postion and send if changed.
|
||||
Only gets triggered when 1st client attaches
|
||||
:param request: request from client
|
||||
:param path: not used - future to register for a different end point
|
||||
:return:
|
||||
"""
|
||||
log.debug("web socket handler registered with client")
|
||||
previous_poll = None
|
||||
previous_main_poll = None
|
||||
if path == '/poll':
|
||||
while True:
|
||||
current_poll = OpenLPPoll().poll()
|
||||
if current_poll != previous_poll:
|
||||
await request.send(current_poll)
|
||||
previous_poll = current_poll
|
||||
await asyncio.sleep(0.2)
|
||||
elif path == '/main_poll':
|
||||
while True:
|
||||
main_poll = OpenLPPoll().main_poll()
|
||||
if main_poll != previous_main_poll:
|
||||
await request.send(main_poll)
|
||||
previous_main_poll = main_poll
|
||||
await asyncio.sleep(0.2)
|
||||
|
||||
def stop_server(self):
|
||||
"""
|
||||
Stop the server
|
||||
@ -237,13 +177,3 @@ class HTTPSServer(HTTPServer):
|
||||
server_side=True)
|
||||
self.server_bind()
|
||||
self.server_activate()
|
||||
|
||||
|
||||
def get_cert_file(file_type):
|
||||
"""
|
||||
Helper method to get certificate files
|
||||
:param file_type: file suffix key, cert or pem
|
||||
:return: full path to file
|
||||
"""
|
||||
local_data = AppLocation.get_directory(AppLocation.DataDir)
|
||||
return os.path.join(local_data, 'remotes', 'openlp.{type}'.format(type=file_type))
|
||||
|
@ -63,7 +63,6 @@ class RemotesPlugin(Plugin, OpenLPMixin):
|
||||
"""
|
||||
super(RemotesPlugin, self).initialise()
|
||||
self.server = OpenLPServer()
|
||||
self.server_ws = OpenLPServer(websocket=True)
|
||||
self.server_secure = OpenLPServer(secure=True)
|
||||
if not hasattr(self, 'remote_server_icon'):
|
||||
self.remote_server_icon = QtWidgets.QLabel(self.main_window.status_bar)
|
||||
|
Loading…
Reference in New Issue
Block a user