Switch to a hacky custom router for plugin web apps

This commit is contained in:
Tulir Asokan 2019-03-06 23:16:22 +02:00
parent a4cfb97b67
commit 3c2d0a9fde
3 changed files with 19 additions and 12 deletions

View file

@ -28,8 +28,8 @@ server:
base_path: /_matrix/maubot/v1 base_path: /_matrix/maubot/v1
# The base path for the UI. # The base path for the UI.
ui_base_path: /_matrix/maubot ui_base_path: /_matrix/maubot
# The base path for plugin endpoints. {id} is replaced with the ID of the instance. # The base path for plugin endpoints. The instance ID will be appended directly.
plugin_base_path: /_matrix/maubot/plugin/{id} plugin_base_path: /_matrix/maubot/plugin/
# Override path from where to load UI resources. # Override path from where to load UI resources.
# Set to false to using pkg_resources to find the path. # Set to false to using pkg_resources to find the path.
override_resource_path: /opt/maubot/frontend override_resource_path: /opt/maubot/frontend

View file

@ -28,8 +28,8 @@ server:
base_path: /_matrix/maubot/v1 base_path: /_matrix/maubot/v1
# The base path for the UI. # The base path for the UI.
ui_base_path: /_matrix/maubot ui_base_path: /_matrix/maubot
# The base path for plugin endpoints. {id} is replaced with the ID of the instance. # The base path for plugin endpoints. The instance ID will be appended directly.
plugin_base_path: /_matrix/maubot/plugin/{id} plugin_base_path: /_matrix/maubot/plugin/
# Override path from where to load UI resources. # Override path from where to load UI resources.
# Set to false to using pkg_resources to find the path. # Set to false to using pkg_resources to find the path.
override_resource_path: false override_resource_path: false

View file

@ -13,12 +13,11 @@
# #
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
from typing import Tuple from typing import Tuple, Dict
import logging import logging
import asyncio import asyncio
from aiohttp import web from aiohttp import web
from aiohttp.web_urldispatcher import PrefixedSubAppResource
from aiohttp.abc import AbstractAccessLogger from aiohttp.abc import AbstractAccessLogger
import pkg_resources import pkg_resources
@ -45,27 +44,35 @@ class MaubotServer:
as_path = PathBuilder(config["server.appservice_base_path"]) as_path = PathBuilder(config["server.appservice_base_path"])
self.add_route(Method.PUT, as_path.transactions, self.handle_transaction) self.add_route(Method.PUT, as_path.transactions, self.handle_transaction)
self.subapps = {}
self.plugin_apps: Dict[str, web.Application] = {}
self.app.router.add_view(config["server.plugin_base_path"], self.handle_plugin_path)
self.setup_management_ui() self.setup_management_ui()
self.runner = web.AppRunner(self.app, access_log_class=AccessLogger) self.runner = web.AppRunner(self.app, access_log_class=AccessLogger)
async def handle_plugin_path(self, request: web.Request) -> web.Response:
for path, app in self.plugin_apps.items():
if request.path.startswith(path):
# TODO there's probably a correct way to do these
request._rel_url.path = request._rel_url.path[len(path):]
return await app._handle(request)
return web.Response(status=404)
def get_instance_subapp(self, instance_id: str) -> Tuple[web.Application, str]: def get_instance_subapp(self, instance_id: str) -> Tuple[web.Application, str]:
subpath = self.config["server.plugin_base_path"].format(id=instance_id) subpath = self.config["server.plugin_base_path"].format(id=instance_id)
url = self.config["server.public_url"] + subpath url = self.config["server.public_url"] + subpath
try: try:
return self.subapps[instance_id], url return self.plugin_apps[subpath], url
except KeyError: except KeyError:
app = web.Application(loop=self.loop) app = web.Application(loop=self.loop)
resource = PrefixedSubAppResource(subpath, app) self.plugin_apps[subpath] = app
self.app.router.register_resource(resource)
self.subapps[instance_id] = app
return app, url return app, url
def remove_instance_webapp(self, instance_id: str) -> None: def remove_instance_webapp(self, instance_id: str) -> None:
try: try:
subapp: web.Application = self.subapps.pop(instance_id) subapp: web.Application = self.plugin_apps.pop(instance_id)
except KeyError: except KeyError:
return return
subapp.shutdown() subapp.shutdown()