1
0
mirror of https://github.com/TeamNewPipe/CrashReportImporter synced 2025-10-06 00:22:39 +02:00
Files
TheAssassin 54e4cab7da Set up LMTP server manually
The controller is meant for running the controller in a separate thread which is unnecessary in this project.
2025-01-01 18:35:02 +01:00

156 lines
4.3 KiB
Python

import asyncio
import functools
import os
from datetime import datetime
from smtplib import LMTP
import click
import sentry_sdk
from sentry_sdk.integrations.asyncio import AsyncioIntegration
from newpipe_crash_report_importer.lmtp_server import CustomLMTP
from . import (
DatabaseEntry,
DirectoryStorage,
GlitchtipStorage,
GlitchtipError,
AlreadyStoredError,
CrashReportHandler,
Message,
make_logger,
configure_logging,
)
logger = make_logger("cli")
class UnknownPackageError(RuntimeError):
pass
@click.group()
@click.option("--force-colors", type=bool, default=False)
def cli(force_colors):
"""
Placeholder. Allows integration the subcommands.
"""
configure_logging(force_colors=force_colors)
@cli.command()
@click.option("--host", type=str, default="::1")
@click.option("--port", type=int, default=8025)
def serve(host, port):
# report errors in the importer to GlitchTip, too
own_dsn = os.environ["OWN_DSN"]
print(f"Reporting own errors to Sentry DSN {own_dsn}")
sentry_sdk.init(
dsn=own_dsn,
debug=os.environ.get("DEBUG_SENTRY_SDK", False),
integrations=[
AsyncioIntegration()
],
)
# initialize storages
directory_storage = DirectoryStorage("mails")
newpipe_dsn = os.environ["NEWPIPE_DSN"]
newpipe_legacy_dsn = os.environ["NEWPIPE_LEGACY_DSN"]
sentry_storage = GlitchtipStorage(newpipe_dsn, "org.schabi.newpipe")
legacy_storage = GlitchtipStorage(newpipe_legacy_dsn, "org.schabi.newpipelegacy")
# define handler code as closure
# TODO: this is not very elegant, should be refactored
async def handle_received_mail(message: Message):
logger.info(f"Handling mail")
try:
entry = DatabaseEntry(message)
except:
logger.exception("Error while parsing the message")
return
logger.info(f"Entry date: {entry.date}")
if entry.date.timestamp() > datetime.now().timestamp():
logger.error("Exception occured in the future... How could that happen?")
return
try:
await directory_storage.save(entry)
except AlreadyStoredError:
logger.warning("Already stored in directory storage, skipping")
package = entry.newpipe_exception_info["package"]
try:
if package == "org.schabi.newpipe":
await sentry_storage.save(entry)
elif package == "org.schabi.newpipelegacy":
await legacy_storage.save(entry)
else:
raise UnknownPackageError("Unknown package: " + package)
except AlreadyStoredError:
logger.warning("Already stored in GlitchTip storage, skipping")
except GlitchtipError as e:
logger.error("Failed to store error in GlitchTip: %s", e)
handler = CrashReportHandler(handle_received_mail)
loop = asyncio.new_event_loop()
loop.run_until_complete(
loop.create_server(
functools.partial(
CustomLMTP,
handler,
ident="NewPipe crash report importer",
enable_SMTPUTF8=True,
),
host=host,
port=port,
)
)
logger.info(f"server listening on {host}:{port}")
loop.run_forever()
# note that import is a protected keyword, so we have to specify the command name explicitly
@cli.command("import")
@click.argument("filenames", type=click.Path(exists=True), nargs=-1)
@click.option("--host", type=str, default="::1")
@click.option("--port", type=int, default=8025)
def import_rfc822(filenames, host, port):
logger.info(f"Connecting to LMTP server {host}:{port}")
client = LMTP(host=host, port=port)
for filename in filenames:
try:
with open(filename) as f:
data = f.read()
except UnicodeDecodeError:
logger.exception("Failed to decode mail contents, skipping")
try:
logger.info(f"Importing RFC822 e-mail file {filename}")
client.sendmail("a@b.cde", ["crashreport@newpipe.net"], data)
except KeyboardInterrupt:
logger.error("SIGINT received, exiting")
return 1
except:
logger.exception("Error while trying to import RFC822 e-mail")
if __name__ == "__main__":
cli()