Repository: lnbits/lnbits

Issue:
Poetry does not gracefully shutdown on CTRL+C
This is a bit critical, bad things can happen if LNbits is just killed without finishing off all routines.

Poetry with `poetry run lnbits`:
<img width="700" alt="image" src="https://user-images.githubusercontent.com/93376500/182562297-6850567b-6fb3-4003-ac9c-317d92392b04.png">

Running lnbits using `./venv/bin/uvicorn lnbits.__main__:app`:
<img width="671" alt="image" src="https://user-images.githubusercontent.com/93376500/182562341-b4d56bfa-bf4f-4981-84e6-06678923439f.png">



Discussion:

Resolving patch:
diff --git a/build.py b/build.py
--- a/build.py
+++ b/build.py
@@ -8,6 +8,7 @@
 
 LNBITS_PATH = path.dirname(path.realpath(__file__)) + "/lnbits"
 
+
 def get_js_vendored(prefer_minified: bool = False) -> List[str]:
     paths = get_vendored(".js", prefer_minified)
 
@@ -71,6 +72,7 @@ def get_vendored(ext: str, prefer_minified: bool = False) -> List[str]:
 def url_for_vendored(abspath: str) -> str:
     return "/" + os.path.relpath(abspath, LNBITS_PATH)
 
+
 def transpile_scss():
     with warnings.catch_warnings():
         warnings.simplefilter("ignore")
@@ -80,6 +82,7 @@ def transpile_scss():
             with open(os.path.join(LNBITS_PATH, "static/css/base.css"), "w") as css:
                 css.write(compile_string(scss.read()))
 
+
 def bundle_vendored():
     for getfiles, outputpath in [
         (get_js_vendored, os.path.join(LNBITS_PATH, "static/bundle.js")),
@@ -96,15 +99,7 @@ def bundle_vendored():
 def build():
     transpile_scss()
     bundle_vendored()
-#    root = Path("lnbits/static/foo")
-#    root.mkdir(parents=True)
-#    root.joinpath("example.css").write_text("")
 
-if __name__ == "__main__":
-   build()
 
-#def build(setup_kwargs):
-#    """Build """
-#    transpile_scss()
-#    bundle_vendored()
-#    subprocess.run(["ls", "-la", "./lnbits/static"])
+if __name__ == "__main__":
+    build()
diff --git a/lnbits/server.py b/lnbits/server.py
--- a/lnbits/server.py
+++ b/lnbits/server.py
@@ -1,18 +1,45 @@
+import time
+
 import click
 import uvicorn
 
+from lnbits.settings import HOST, PORT
+
 
-@click.command()
-@click.option("--port", default="5000", help="Port to run LNBits on")
-@click.option("--host", default="127.0.0.1", help="Host to run LNBits on")
-def main(port, host):
+@click.command(
+    context_settings=dict(
+        ignore_unknown_options=True,
+        allow_extra_args=True,
+    )
+)
+@click.option("--port", default=PORT, help="Port to listen on")
+@click.option("--host", default=HOST, help="Host to run LNBits on")
+@click.option("--ssl-keyfile", default=None, help="Path to SSL keyfile")
+@click.option("--ssl-certfile", default=None, help="Path to SSL certificate")
+@click.pass_context
+def main(ctx, port: int, host: str, ssl_keyfile: str, ssl_certfile: str):
     """Launched with `poetry run lnbits` at root level"""
-    uvicorn.run("lnbits.__main__:app", port=port, host=host)
+    # this beautiful beast parses all command line arguments and passes them to the uvicorn server
+    d = dict(
+        [
+            (
+                item[0].strip("--").replace("-", "_"),
+                int(item[1]) if item[1].isdigit() else item[1],
+            )
+            for item in zip(*[iter(ctx.args)] * 2)
+        ]
+    )
+    config = uvicorn.Config(
+        "lnbits.__main__:app",
+        port=port,
+        host=host,
+        ssl_keyfile=ssl_keyfile,
+        ssl_certfile=ssl_certfile,
+        **d
+    )
+    server = uvicorn.Server(config)
+    server.run()
 
 
 if __name__ == "__main__":
     main()
-
-# def main():
-#    """Launched with `poetry run start` at root level"""
-#    uvicorn.run("lnbits.__main__:app")


Test patch: