From 37226f4cd560d720880d06b74abc44c6870233fb Mon Sep 17 00:00:00 2001
From: Reid 'arrdem' McKenzie <me@arrdem.com>
Date: Sat, 3 Jun 2023 10:31:11 -0600
Subject: [PATCH 1/2] Pull in aiosql; the anosql heir

---
 tools/python/requirements.in       | 1 +
 tools/python/requirements_lock.txt | 1 +
 2 files changed, 2 insertions(+)

diff --git a/tools/python/requirements.in b/tools/python/requirements.in
index 8705e45..f48906d 100644
--- a/tools/python/requirements.in
+++ b/tools/python/requirements.in
@@ -1,5 +1,6 @@
 -c constraints.in
 
+aiosql
 ExifRead
 aiohttp
 aiohttp_basicauth
diff --git a/tools/python/requirements_lock.txt b/tools/python/requirements_lock.txt
index fd233f9..5c93185 100644
--- a/tools/python/requirements_lock.txt
+++ b/tools/python/requirements_lock.txt
@@ -1,6 +1,7 @@
 aiohttp==3.8.4
 aiohttp-basicauth==1.0.0
 aiosignal==1.3.1
+aiosql==8.0
 alabaster==0.7.13
 async-lru==2.0.2
 async-timeout==4.0.2

From e0b97f5f7a71829fe760e81715d065e31dafc71c Mon Sep 17 00:00:00 2001
From: Reid 'arrdem' McKenzie <me@arrdem.com>
Date: Sat, 3 Jun 2023 10:34:25 -0600
Subject: [PATCH 2/2] Embed cherrypy directly

---
 projects/tentacles/BUILD                      |  2 +-
 .../src/python/tentacles/__main__.py          | 72 +++++++++++++------
 .../tentacles/src/python/tentacles/workers.py | 34 ++++-----
 3 files changed, 68 insertions(+), 40 deletions(-)

diff --git a/projects/tentacles/BUILD b/projects/tentacles/BUILD
index 336cd7d..4febfd8 100644
--- a/projects/tentacles/BUILD
+++ b/projects/tentacles/BUILD
@@ -6,12 +6,12 @@ py_project(
     main_deps = [
         "//projects/anosql",
         "//projects/anosql-migrations",
-        "//projects/cherry-shim",
         py_requirement("attrs"),
         py_requirement("click"),
         py_requirement("flask"),
         py_requirement("jinja2"),
         py_requirement("octorest"),
+        py_requirement("cherrypy"),
     ],
     lib_data = [
         "//projects/tentacles/src/python/tentacles/static/css",
diff --git a/projects/tentacles/src/python/tentacles/__main__.py b/projects/tentacles/src/python/tentacles/__main__.py
index 506aa0a..370915a 100644
--- a/projects/tentacles/src/python/tentacles/__main__.py
+++ b/projects/tentacles/src/python/tentacles/__main__.py
@@ -3,13 +3,13 @@
 """The core app entrypoint."""
 
 from datetime import datetime
+import logging
 from pathlib import Path
 import tomllib
 
+import cherrypy
 import click
 from flask import Flask, request
-
-from cherry_shim import shim
 from tentacles.blueprints import (
     api,
     file_ui,
@@ -19,7 +19,7 @@ from tentacles.blueprints import (
 )
 from tentacles.globals import _ctx, Ctx, ctx
 from tentacles.store import Store
-from tentacles.workers import create_workers
+from tentacles.workers import Worker
 
 
 @click.group()
@@ -27,7 +27,7 @@ def cli():
     pass
 
 
-def store_factory(app):
+def db_factory(app):
     store = Store(app.config.get("db", {}).get("uri"))
     store.connect()
     return store
@@ -35,7 +35,7 @@ def store_factory(app):
 
 def custom_ctx(app, wsgi_app):
     def helper(environ, start_response):
-        store = store_factory(app)
+        store = db_factory(app)
         token = _ctx.set(Ctx(store))
         try:
             return wsgi_app(environ, start_response)
@@ -76,21 +76,11 @@ def user_session():
         ctx.is_admin = user.group_id == 0
 
 
-@cli.command()
-@click.option("--hostname", "hostname", type=str, default="0.0.0.0")
-@click.option("--port", "port", type=int, default=8080)
-@click.option("--config", type=Path)
-def serve(hostname: str, port: int, config: Path):
+def make_app():
     app = Flask(__name__)
-    if config:
-        with open(config, "rb") as fp:
-            app.config.update(tomllib.load(fp))
-
-    print(app.config)
 
     # Before first request
     create_j2_request_global(app)
-    shutdown_event = create_workers(app, store_factory)
 
     # Before request
     app.before_request(user_session)
@@ -104,13 +94,51 @@ def serve(hostname: str, port: int, config: Path):
 
     # Shove our middleware in there
     app.wsgi_app = custom_ctx(app, app.wsgi_app)
-    cherry = shim(app)
 
-    # And run the blame thing
-    try:
-        cherry.run(host=hostname, port=port)
-    finally:
-        shutdown_event.set()
+    return app
+
+
+@cli.command()
+@click.option("--hostname", "hostname", type=str, default="0.0.0.0")
+@click.option("--port", "port", type=int, default=8080)
+@click.option("--config", type=Path)
+def serve(hostname: str, port: int, config: Path):
+    logging.basicConfig(
+        format="%(asctime)s %(relativeCreated)6d %(threadName)s - %(name)s - %(levelname)s -  %(message)s",
+        level=logging.INFO,
+    )
+
+    logging.getLogger("tentacles").setLevel(logging.DEBUG)
+
+    app = make_app()
+
+    if config:
+        with open(config, "rb") as fp:
+            app.config.update(tomllib.load(fp))
+    print(app.config)
+
+    cherrypy.server.unsubscribe()
+    server = cherrypy._cpserver.Server()
+    cherrypy.config.update(
+        {
+            "environment": "production",
+            "engine.autoreload.on": False,
+        }
+    )
+    cherrypy.tree.graft(app, "/")
+
+    server.socket_host = hostname
+    server.socket_port = port
+    server.thread_pool = 16
+    server.shutdown_timeout = 1
+    server.subscribe()
+
+    # Spawn the worker thread
+    Worker(cherrypy.engine, app, db_factory, frequency=5).start()
+
+    # Run the server
+    cherrypy.engine.start()
+    cherrypy.engine.block()
 
 
 if __name__ == "__main__":
diff --git a/projects/tentacles/src/python/tentacles/workers.py b/projects/tentacles/src/python/tentacles/workers.py
index 410efca..6dafcdd 100644
--- a/projects/tentacles/src/python/tentacles/workers.py
+++ b/projects/tentacles/src/python/tentacles/workers.py
@@ -11,13 +11,13 @@ from contextlib import closing
 from datetime import datetime, timedelta
 import logging
 from pathlib import Path
-from threading import Event, Thread
+from threading import Event
 from time import sleep
-from typing import Callable
 from urllib import parse as urlparse
 
+from cherrypy.process.plugins import Monitor
 from fastmail import FastMailSMTP
-from flask import Flask as App, render_template
+from flask import Flask as App
 from octorest import OctoRest as _OR
 from requests import Response
 from requests.exceptions import (
@@ -271,18 +271,18 @@ def send_emails(app, store: Store):
             store.send_email(message.id)
 
 
-@corn_job(timedelta(seconds=5))
-def run_worker(app: App, db_factory):
-    with app.app_context(), closing(db_factory(app)) as store:
-        poll_printers(app, store)
-        assign_jobs(app, store)
-        push_jobs(app, store)
-        revoke_jobs(app, store)
-        pull_jobs(app, store)
-        send_emails(app, store)
+class Worker(Monitor):
+    def __init__(self, bus, app, db_factory, **kwargs):
+        self._app = app
+        self._db_factory = db_factory
+        super().__init__(bus, self.callback, **kwargs)
 
-
-def create_workers(app, db_factory: Callable[[App], Store]) -> Event:
-    Thread(target=run_worker, args=[app, db_factory]).start()
-
-    return SHUTDOWN
+    def callback(self):
+        log.debug("Tick")
+        with self._app.app_context(), closing(self._db_factory(self._app)) as store:
+            poll_printers(self._app, store)
+            assign_jobs(self._app, store)
+            push_jobs(self._app, store)
+            revoke_jobs(self._app, store)
+            pull_jobs(self._app, store)
+            send_emails(self._app, store)