2021-03-24 09:49:43 -03:00
|
|
|
|
import sys
|
2020-10-12 22:25:55 -03:00
|
|
|
|
import warnings
|
2021-05-06 23:22:02 -03:00
|
|
|
|
import importlib
|
|
|
|
|
import traceback
|
2020-09-05 08:00:44 +02:00
|
|
|
|
|
2020-10-03 21:57:14 -03:00
|
|
|
|
from quart import g
|
|
|
|
|
from quart_trio import QuartTrio
|
2020-09-13 21:31:05 -03:00
|
|
|
|
from quart_cors import cors # type: ignore
|
|
|
|
|
from quart_compress import Compress # type: ignore
|
2020-09-05 08:00:44 +02:00
|
|
|
|
|
2020-09-28 23:11:59 +02:00
|
|
|
|
from .commands import db_migrate, handle_assets
|
2020-09-05 08:00:44 +02:00
|
|
|
|
from .core import core_app
|
2021-03-24 00:40:32 -03:00
|
|
|
|
from .helpers import (
|
|
|
|
|
get_valid_extensions,
|
|
|
|
|
get_js_vendored,
|
|
|
|
|
get_css_vendored,
|
|
|
|
|
url_for_vendored,
|
|
|
|
|
)
|
2020-09-28 00:21:33 -03:00
|
|
|
|
from .proxy_fix import ASGIProxyFix
|
2021-03-21 17:57:33 -03:00
|
|
|
|
from .tasks import (
|
|
|
|
|
run_deferred_async,
|
|
|
|
|
check_pending_payments,
|
|
|
|
|
invoice_listener,
|
|
|
|
|
internal_invoice_listener,
|
|
|
|
|
webhook_handler,
|
|
|
|
|
)
|
2020-10-12 22:25:55 -03:00
|
|
|
|
from .settings import WALLET
|
2020-09-05 08:00:44 +02:00
|
|
|
|
|
2020-09-13 21:31:05 -03:00
|
|
|
|
|
2020-10-03 21:57:14 -03:00
|
|
|
|
def create_app(config_object="lnbits.settings") -> QuartTrio:
|
2020-09-13 21:31:05 -03:00
|
|
|
|
"""Create application factory.
|
2020-09-05 08:00:44 +02:00
|
|
|
|
:param config_object: The configuration object to use.
|
|
|
|
|
"""
|
2020-10-03 21:57:14 -03:00
|
|
|
|
app = QuartTrio(__name__, static_folder="static")
|
2020-09-05 08:00:44 +02:00
|
|
|
|
app.config.from_object(config_object)
|
2020-09-28 00:21:33 -03:00
|
|
|
|
app.asgi_http_class = ASGIProxyFix
|
2020-09-05 08:00:44 +02:00
|
|
|
|
|
2020-09-13 21:31:05 -03:00
|
|
|
|
cors(app)
|
|
|
|
|
Compress(app)
|
|
|
|
|
|
2020-10-12 22:25:55 -03:00
|
|
|
|
check_funding_source(app)
|
2020-09-15 15:54:05 -03:00
|
|
|
|
register_assets(app)
|
2020-09-05 08:00:44 +02:00
|
|
|
|
register_blueprints(app)
|
|
|
|
|
register_filters(app)
|
|
|
|
|
register_commands(app)
|
2020-09-27 23:12:55 -03:00
|
|
|
|
register_async_tasks(app)
|
2021-05-06 23:22:02 -03:00
|
|
|
|
register_exception_handlers(app)
|
2020-09-05 08:00:44 +02:00
|
|
|
|
|
|
|
|
|
return app
|
|
|
|
|
|
|
|
|
|
|
2020-10-12 22:25:55 -03:00
|
|
|
|
def check_funding_source(app: QuartTrio) -> None:
|
|
|
|
|
@app.before_serving
|
|
|
|
|
async def check_wallet_status():
|
2021-03-24 01:01:09 -03:00
|
|
|
|
error_message, balance = await WALLET.status()
|
2020-10-12 22:25:55 -03:00
|
|
|
|
if error_message:
|
|
|
|
|
warnings.warn(
|
|
|
|
|
f" × The backend for {WALLET.__class__.__name__} isn't working properly: '{error_message}'",
|
|
|
|
|
RuntimeWarning,
|
|
|
|
|
)
|
2021-03-24 09:49:43 -03:00
|
|
|
|
|
|
|
|
|
sys.exit(4)
|
2020-10-12 22:25:55 -03:00
|
|
|
|
else:
|
2021-03-24 00:40:32 -03:00
|
|
|
|
print(
|
|
|
|
|
f" ✔️ {WALLET.__class__.__name__} seems to be connected and with a balance of {balance} msat."
|
|
|
|
|
)
|
2020-10-12 22:25:55 -03:00
|
|
|
|
|
|
|
|
|
|
2020-10-03 21:57:14 -03:00
|
|
|
|
def register_blueprints(app: QuartTrio) -> None:
|
2020-09-05 08:00:44 +02:00
|
|
|
|
"""Register Flask blueprints / LNbits extensions."""
|
|
|
|
|
app.register_blueprint(core_app)
|
|
|
|
|
|
|
|
|
|
for ext in get_valid_extensions():
|
|
|
|
|
try:
|
|
|
|
|
ext_module = importlib.import_module(f"lnbits.extensions.{ext.code}")
|
2020-10-02 17:12:49 -03:00
|
|
|
|
bp = getattr(ext_module, f"{ext.code}_ext")
|
|
|
|
|
|
|
|
|
|
app.register_blueprint(bp, url_prefix=f"/{ext.code}")
|
2020-09-05 08:00:44 +02:00
|
|
|
|
except Exception:
|
2021-03-24 00:40:32 -03:00
|
|
|
|
raise ImportError(
|
|
|
|
|
f"Please make sure that the extension `{ext.code}` follows conventions."
|
|
|
|
|
)
|
2020-09-05 08:00:44 +02:00
|
|
|
|
|
|
|
|
|
|
2020-10-03 21:57:14 -03:00
|
|
|
|
def register_commands(app: QuartTrio):
|
2020-09-05 08:00:44 +02:00
|
|
|
|
"""Register Click commands."""
|
2020-09-13 21:31:05 -03:00
|
|
|
|
app.cli.add_command(db_migrate)
|
2020-09-28 23:11:59 +02:00
|
|
|
|
app.cli.add_command(handle_assets)
|
2020-09-05 08:00:44 +02:00
|
|
|
|
|
|
|
|
|
|
2020-10-03 21:57:14 -03:00
|
|
|
|
def register_assets(app: QuartTrio):
|
2020-09-15 15:54:05 -03:00
|
|
|
|
"""Serve each vendored asset separately or a bundle."""
|
|
|
|
|
|
|
|
|
|
@app.before_request
|
|
|
|
|
async def vendored_assets_variable():
|
|
|
|
|
if app.config["DEBUG"]:
|
|
|
|
|
g.VENDORED_JS = map(url_for_vendored, get_js_vendored())
|
|
|
|
|
g.VENDORED_CSS = map(url_for_vendored, get_css_vendored())
|
|
|
|
|
else:
|
|
|
|
|
g.VENDORED_JS = ["/static/bundle.js"]
|
|
|
|
|
g.VENDORED_CSS = ["/static/bundle.css"]
|
|
|
|
|
|
|
|
|
|
|
2020-10-03 21:57:14 -03:00
|
|
|
|
def register_filters(app: QuartTrio):
|
2020-09-05 08:00:44 +02:00
|
|
|
|
"""Jinja filters."""
|
|
|
|
|
app.jinja_env.globals["SITE_TITLE"] = app.config["LNBITS_SITE_TITLE"]
|
2021-07-02 12:31:05 +01:00
|
|
|
|
app.jinja_env.globals["SITE_TAGLINE"] = app.config["LNBITS_SITE_TAGLINE"]
|
|
|
|
|
app.jinja_env.globals["SITE_DESCRIPTION"] = app.config["LNBITS_SITE_DESCRIPTION"]
|
2021-06-30 17:00:56 +01:00
|
|
|
|
app.jinja_env.globals["LNBITS_THEME_OPTIONS"] = app.config["LNBITS_THEME_OPTIONS"]
|
2021-06-10 11:51:57 +01:00
|
|
|
|
app.jinja_env.globals["LNBITS_VERSION"] = app.config["LNBITS_COMMIT"]
|
2020-09-15 15:54:05 -03:00
|
|
|
|
app.jinja_env.globals["EXTENSIONS"] = get_valid_extensions()
|
2020-09-07 00:47:13 -03:00
|
|
|
|
|
|
|
|
|
|
2020-09-27 23:12:55 -03:00
|
|
|
|
def register_async_tasks(app):
|
2020-09-29 00:52:27 -03:00
|
|
|
|
@app.route("/wallet/webhook", methods=["GET", "POST", "PUT", "PATCH", "DELETE"])
|
2020-09-27 23:12:55 -03:00
|
|
|
|
async def webhook_listener():
|
|
|
|
|
return await webhook_handler()
|
|
|
|
|
|
|
|
|
|
@app.before_serving
|
|
|
|
|
async def listeners():
|
2020-10-06 01:50:55 -03:00
|
|
|
|
run_deferred_async(app.nursery)
|
2021-03-21 17:57:33 -03:00
|
|
|
|
app.nursery.start_soon(check_pending_payments)
|
|
|
|
|
app.nursery.start_soon(invoice_listener, app.nursery)
|
|
|
|
|
app.nursery.start_soon(internal_invoice_listener, app.nursery)
|
2020-09-27 23:12:55 -03:00
|
|
|
|
|
|
|
|
|
@app.after_serving
|
|
|
|
|
async def stop_listeners():
|
|
|
|
|
pass
|
2021-05-06 23:22:02 -03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def register_exception_handlers(app):
|
|
|
|
|
@app.errorhandler(Exception)
|
|
|
|
|
async def basic_error(err):
|
|
|
|
|
etype, value, tb = sys.exc_info()
|
|
|
|
|
traceback.print_exception(etype, err, tb)
|
|
|
|
|
exc = traceback.format_exc()
|
|
|
|
|
return (
|
|
|
|
|
"\n\n".join(
|
|
|
|
|
[
|
|
|
|
|
"LNbits internal error!",
|
|
|
|
|
exc,
|
|
|
|
|
"If you believe this shouldn't be an error please bring it up on https://t.me/lnbits",
|
|
|
|
|
]
|
|
|
|
|
),
|
|
|
|
|
500,
|
|
|
|
|
)
|