mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-25 05:14:40 +01:00
changed webserver from addon to feature of tray
This commit is contained in:
parent
f6cca927e1
commit
f80b82add9
7 changed files with 99 additions and 122 deletions
|
|
@ -1,5 +1,7 @@
|
|||
import time
|
||||
|
||||
from ayon_core.addon import AddonsManager, ITrayAddon, ITrayService
|
||||
from ayon_core.tools.tray.webserver import TrayWebserver
|
||||
|
||||
|
||||
class TrayAddonsManager(AddonsManager):
|
||||
|
|
@ -16,10 +18,15 @@ class TrayAddonsManager(AddonsManager):
|
|||
super().__init__(initialize=False)
|
||||
|
||||
self._tray_manager = tray_manager
|
||||
self._tray_webserver = None
|
||||
|
||||
self.doubleclick_callbacks = {}
|
||||
self.doubleclick_callback = None
|
||||
|
||||
def get_doubleclick_callback(self):
|
||||
callback_name = self.doubleclick_callback
|
||||
return self.doubleclick_callbacks.get(callback_name)
|
||||
|
||||
def add_doubleclick_callback(self, addon, callback):
|
||||
"""Register double-click callbacks on tray icon.
|
||||
|
||||
|
|
@ -68,6 +75,7 @@ class TrayAddonsManager(AddonsManager):
|
|||
self._tray_manager.restart()
|
||||
|
||||
def tray_init(self):
|
||||
self._tray_webserver = TrayWebserver(self._tray_manager)
|
||||
report = {}
|
||||
time_start = time.time()
|
||||
prev_start_time = time_start
|
||||
|
|
@ -92,6 +100,11 @@ class TrayAddonsManager(AddonsManager):
|
|||
report[self._report_total_key] = time.time() - time_start
|
||||
self._report["Tray init"] = report
|
||||
|
||||
def connect_addons(self):
|
||||
enabled_addons = self.get_enabled_addons()
|
||||
self._tray_webserver.connect_with_addons(enabled_addons)
|
||||
super().connect_addons()
|
||||
|
||||
def tray_menu(self, tray_menu):
|
||||
ordered_addons = []
|
||||
enabled_by_name = {
|
||||
|
|
@ -132,6 +145,7 @@ class TrayAddonsManager(AddonsManager):
|
|||
self._report["Tray menu"] = report
|
||||
|
||||
def start_addons(self):
|
||||
self._tray_webserver.start()
|
||||
report = {}
|
||||
time_start = time.time()
|
||||
prev_start_time = time_start
|
||||
|
|
@ -159,6 +173,7 @@ class TrayAddonsManager(AddonsManager):
|
|||
self._report["Addons start"] = report
|
||||
|
||||
def on_exit(self):
|
||||
self._tray_webserver.stop()
|
||||
for addon in self.get_enabled_tray_addons():
|
||||
if addon.tray_initialized:
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -1,13 +1,8 @@
|
|||
from .version import __version__
|
||||
from .structures import HostMsgAction
|
||||
from .webserver_module import (
|
||||
WebServerAddon
|
||||
)
|
||||
from .webserver_module import TrayWebserver
|
||||
|
||||
|
||||
__all__ = (
|
||||
"__version__",
|
||||
|
||||
"HostMsgAction",
|
||||
"WebServerAddon",
|
||||
"TrayWebserver",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
"""Helper functions or classes for Webserver module.
|
||||
|
||||
These must not be imported in module itself to not break Python 2
|
||||
applications.
|
||||
These must not be imported in module itself to not break in-DCC process.
|
||||
"""
|
||||
|
||||
import inspect
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@ class IconType:
|
|||
|
||||
|
||||
class HostListener:
|
||||
def __init__(self, webserver, module):
|
||||
def __init__(self, webserver, tray_manager):
|
||||
self._window_per_id = {}
|
||||
self.module = module
|
||||
self._tray_manager = tray_manager
|
||||
self.webserver = webserver
|
||||
self._window_per_id = {} # dialogs per host name
|
||||
self._action_per_id = {} # QAction per host name
|
||||
|
|
@ -32,8 +32,9 @@ class HostListener:
|
|||
webserver.add_route('*', "/ws/host_listener", self.websocket_handler)
|
||||
|
||||
def _host_is_connecting(self, host_name, label):
|
||||
""" Initialize dialog, adds to submenu. """
|
||||
services_submenu = self.module._services_submenu
|
||||
""" Initialize dialog, adds to submenu."""
|
||||
ITrayService.services_submenu(self._tray_manager)
|
||||
services_submenu = self._tray_manager.get_services_submenu()
|
||||
action = QtWidgets.QAction(label, services_submenu)
|
||||
action.triggered.connect(lambda: self.show_widget(host_name))
|
||||
|
||||
|
|
@ -73,8 +74,9 @@ class HostListener:
|
|||
|
||||
Dialog get initialized when 'host_name' is connecting.
|
||||
"""
|
||||
self.module.execute_in_main_thread(
|
||||
lambda: self._show_widget(host_name))
|
||||
self._tray_manager.execute_in_main_thread(
|
||||
self._show_widget, host_name
|
||||
)
|
||||
|
||||
def _show_widget(self, host_name):
|
||||
widget = self._window_per_id[host_name]
|
||||
|
|
@ -95,21 +97,23 @@ class HostListener:
|
|||
if action == HostMsgAction.CONNECTING:
|
||||
self._action_per_id[host_name] = None
|
||||
# must be sent to main thread, or action wont trigger
|
||||
self.module.execute_in_main_thread(
|
||||
lambda: self._host_is_connecting(host_name, text))
|
||||
self._tray_manager.execute_in_main_thread(
|
||||
self._host_is_connecting, host_name, text
|
||||
)
|
||||
elif action == HostMsgAction.CLOSE:
|
||||
# clean close
|
||||
self._close(host_name)
|
||||
await ws.close()
|
||||
elif action == HostMsgAction.INITIALIZED:
|
||||
self.module.execute_in_main_thread(
|
||||
self._tray_manager.execute_in_main_thread(
|
||||
# must be queued as _host_is_connecting might not
|
||||
# be triggered/finished yet
|
||||
lambda: self._set_host_icon(host_name,
|
||||
IconType.RUNNING))
|
||||
self._set_host_icon, host_name, IconType.RUNNING
|
||||
)
|
||||
elif action == HostMsgAction.ADD:
|
||||
self.module.execute_in_main_thread(
|
||||
lambda: self._add_text(host_name, text))
|
||||
self._tray_manager.execute_in_main_thread(
|
||||
self._add_text, host_name, text
|
||||
)
|
||||
elif msg.type == aiohttp.WSMsgType.ERROR:
|
||||
print('ws connection closed with exception %s' %
|
||||
ws.exception())
|
||||
|
|
@ -131,7 +135,7 @@ class HostListener:
|
|||
|
||||
def _close(self, host_name):
|
||||
""" Clean close - remove from menu, delete widget."""
|
||||
services_submenu = self.module._services_submenu
|
||||
services_submenu = self._tray_manager.get_services_submenu()
|
||||
action = self._action_per_id.pop(host_name)
|
||||
services_submenu.removeAction(action)
|
||||
widget = self._window_per_id.pop(host_name)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import re
|
||||
import threading
|
||||
import asyncio
|
||||
from typing import Callable, Optional
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
|
|
@ -11,7 +12,9 @@ from .cors_middleware import cors_middleware
|
|||
class WebServerManager:
|
||||
"""Manger that care about web server thread."""
|
||||
|
||||
def __init__(self, port=None, host=None):
|
||||
def __init__(
|
||||
self, port: Optional[int] = None, host: Optional[str] = None
|
||||
):
|
||||
self._log = None
|
||||
|
||||
self.port = port or 8079
|
||||
|
|
@ -40,14 +43,14 @@ class WebServerManager:
|
|||
return self._log
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
return "http://{}:{}".format(self.host, self.port)
|
||||
def url(self) -> str:
|
||||
return f"http://{self.host}:{self.port}"
|
||||
|
||||
def add_route(self, *args, **kwargs):
|
||||
self.app.router.add_route(*args, **kwargs)
|
||||
def add_route(self, request_method: str, path: str, handler: Callable):
|
||||
self.app.router.add_route(request_method, path, handler)
|
||||
|
||||
def add_static(self, *args, **kwargs):
|
||||
self.app.router.add_static(*args, **kwargs)
|
||||
def add_static(self, prefix: str, path: str):
|
||||
self.app.router.add_static(prefix, path)
|
||||
|
||||
def start_server(self):
|
||||
if self.webserver_thread and not self.webserver_thread.is_alive():
|
||||
|
|
@ -68,7 +71,7 @@ class WebServerManager:
|
|||
)
|
||||
|
||||
@property
|
||||
def is_running(self):
|
||||
def is_running(self) -> bool:
|
||||
if not self.webserver_thread:
|
||||
return False
|
||||
return self.webserver_thread.is_running
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
__version__ = "1.0.0"
|
||||
|
|
@ -1,47 +1,62 @@
|
|||
"""WebServerAddon spawns aiohttp server in asyncio loop.
|
||||
"""TrayWebserver spawns aiohttp server in asyncio loop.
|
||||
|
||||
Main usage of the module is in AYON tray where make sense to add ability
|
||||
of other modules to add theirs routes. Module which would want use that
|
||||
option must have implemented method `webserver_initialization` which must
|
||||
expect `WebServerManager` object where is possible to add routes or paths
|
||||
with handlers.
|
||||
Usage is to add ability to register routes from addons, or for inner calls
|
||||
of tray. Addon which would want use that option must have implemented method
|
||||
webserver_initialization` which must expect `WebServerManager` object where
|
||||
is possible to add routes or paths with handlers.
|
||||
|
||||
WebServerManager is by default created only in tray.
|
||||
|
||||
It is possible to create server manager without using module logic at all
|
||||
using `create_new_server_manager`. That can be handy for standalone scripts
|
||||
with predefined host and port and separated routes and logic.
|
||||
|
||||
Running multiple servers in one process is not recommended and probably won't
|
||||
work as expected. It is because of few limitations connected to asyncio module.
|
||||
|
||||
When module's `create_server_manager` is called it is also set environment
|
||||
variable "AYON_WEBSERVER_URL". Which should lead to root access point
|
||||
of server.
|
||||
"""
|
||||
|
||||
import os
|
||||
import socket
|
||||
|
||||
from ayon_core import resources
|
||||
from ayon_core.addon import AYONAddon, ITrayService
|
||||
from ayon_core.lib import Logger
|
||||
|
||||
from .version import __version__
|
||||
from .server import WebServerManager
|
||||
from .host_console_listener import HostListener
|
||||
|
||||
|
||||
class WebServerAddon(AYONAddon, ITrayService):
|
||||
name = "webserver"
|
||||
version = __version__
|
||||
label = "WebServer"
|
||||
|
||||
class TrayWebserver:
|
||||
webserver_url_env = "AYON_WEBSERVER_URL"
|
||||
|
||||
def initialize(self, settings):
|
||||
self._server_manager = None
|
||||
self._host_listener = None
|
||||
|
||||
def __init__(self, tray_manager):
|
||||
self._log = None
|
||||
self._tray_manager = tray_manager
|
||||
self._port = self.find_free_port()
|
||||
self._webserver_url = None
|
||||
|
||||
self._server_manager = WebServerManager(self._port, None)
|
||||
|
||||
webserver_url = self._server_manager.url
|
||||
self._webserver_url = webserver_url
|
||||
|
||||
self._host_listener = HostListener(self, self._tray_manager)
|
||||
|
||||
static_prefix = "/res"
|
||||
self._server_manager.add_static(static_prefix, resources.RESOURCES_DIR)
|
||||
statisc_url = "{}{}".format(
|
||||
self._webserver_url, static_prefix
|
||||
)
|
||||
|
||||
os.environ[self.webserver_url_env] = str(webserver_url)
|
||||
os.environ["AYON_STATICS_SERVER"] = statisc_url
|
||||
|
||||
# Deprecated
|
||||
os.environ["OPENPYPE_WEBSERVER_URL"] = str(webserver_url)
|
||||
os.environ["OPENPYPE_STATICS_SERVER"] = statisc_url
|
||||
|
||||
@property
|
||||
def log(self):
|
||||
if self._log is None:
|
||||
self._log = Logger.get_logger("TrayWebserver")
|
||||
return self._log
|
||||
|
||||
def add_route(self, *args, **kwargs):
|
||||
self._server_manager.add_route(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def server_manager(self):
|
||||
|
|
@ -73,72 +88,36 @@ class WebServerAddon(AYONAddon, ITrayService):
|
|||
"""
|
||||
return self._webserver_url
|
||||
|
||||
def connect_with_addons(self, enabled_modules):
|
||||
def connect_with_addons(self, enabled_addons):
|
||||
if not self._server_manager:
|
||||
return
|
||||
|
||||
for module in enabled_modules:
|
||||
if not hasattr(module, "webserver_initialization"):
|
||||
for addon in enabled_addons:
|
||||
if not hasattr(addon, "webserver_initialization"):
|
||||
continue
|
||||
|
||||
try:
|
||||
module.webserver_initialization(self._server_manager)
|
||||
addon.webserver_initialization(self._server_manager)
|
||||
except Exception:
|
||||
self.log.warning(
|
||||
(
|
||||
"Failed to connect module \"{}\" to webserver."
|
||||
).format(module.name),
|
||||
f"Failed to connect addon \"{addon.name}\" to webserver.",
|
||||
exc_info=True
|
||||
)
|
||||
|
||||
def tray_init(self):
|
||||
self.create_server_manager()
|
||||
self._add_resources_statics()
|
||||
self._add_listeners()
|
||||
def start(self):
|
||||
self._start_server()
|
||||
|
||||
def tray_start(self):
|
||||
self.start_server()
|
||||
def stop(self):
|
||||
self._stop_server()
|
||||
|
||||
def tray_exit(self):
|
||||
self.stop_server()
|
||||
|
||||
def start_server(self):
|
||||
def _start_server(self):
|
||||
if self._server_manager is not None:
|
||||
self._server_manager.start_server()
|
||||
|
||||
def stop_server(self):
|
||||
def _stop_server(self):
|
||||
if self._server_manager is not None:
|
||||
self._server_manager.stop_server()
|
||||
|
||||
@staticmethod
|
||||
def create_new_server_manager(port=None, host=None):
|
||||
"""Create webserver manager for passed port and host.
|
||||
|
||||
Args:
|
||||
port(int): Port on which wil webserver listen.
|
||||
host(str): Host name or IP address. Default is 'localhost'.
|
||||
|
||||
Returns:
|
||||
WebServerManager: Prepared manager.
|
||||
"""
|
||||
from .server import WebServerManager
|
||||
|
||||
return WebServerManager(port, host)
|
||||
|
||||
def create_server_manager(self):
|
||||
if self._server_manager is not None:
|
||||
return
|
||||
|
||||
self._server_manager = self.create_new_server_manager(self._port)
|
||||
self._server_manager.on_stop_callbacks.append(
|
||||
self.set_service_failed_icon
|
||||
)
|
||||
|
||||
webserver_url = self._server_manager.url
|
||||
os.environ["OPENPYPE_WEBSERVER_URL"] = str(webserver_url)
|
||||
os.environ[self.webserver_url_env] = str(webserver_url)
|
||||
self._webserver_url = webserver_url
|
||||
|
||||
@staticmethod
|
||||
def find_free_port(
|
||||
port_from=None, port_to=None, exclude_ports=None, host=None
|
||||
|
|
@ -193,20 +172,3 @@ class WebServerAddon(AYONAddon, ITrayService):
|
|||
break
|
||||
|
||||
return found_port
|
||||
|
||||
def _add_resources_statics(self):
|
||||
static_prefix = "/res"
|
||||
self._server_manager.add_static(static_prefix, resources.RESOURCES_DIR)
|
||||
statisc_url = "{}{}".format(
|
||||
self._webserver_url, static_prefix
|
||||
)
|
||||
|
||||
os.environ["AYON_STATICS_SERVER"] = statisc_url
|
||||
os.environ["OPENPYPE_STATICS_SERVER"] = statisc_url
|
||||
|
||||
def _add_listeners(self):
|
||||
from . import host_console_listener
|
||||
|
||||
self._host_listener = host_console_listener.HostListener(
|
||||
self._server_manager, self
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue