From 0915b17c4b7eb59d73f2524251dfcce9775e3ce2 Mon Sep 17 00:00:00 2001 From: Andrew Godwin Date: Mon, 17 Jul 2023 00:18:00 -0600 Subject: [PATCH] Prune some unnecessary async usage --- activities/models/fan_out.py | 20 ----- activities/models/post.py | 12 --- activities/models/post_interaction.py | 114 ++++++++++-------------- api/models/token.py | 1 - api/schemas.py | 2 +- core/models/config.py | 41 --------- stator/management/commands/runstator.py | 2 +- stator/views.py | 4 +- users/models/block.py | 2 +- users/models/follow.py | 2 +- users/models/identity.py | 2 +- users/models/password_reset.py | 32 +++---- 12 files changed, 63 insertions(+), 171 deletions(-) diff --git a/activities/models/fan_out.py b/activities/models/fan_out.py index 308664b..242de12 100644 --- a/activities/models/fan_out.py +++ b/activities/models/fan_out.py @@ -319,23 +319,3 @@ class FanOut(StatorModel): created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) - - ### Async helpers ### - - async def afetch_full(self): - """ - Returns a version of the object with all relations pre-loaded - """ - return ( - await FanOut.objects.select_related( - "identity", - "subject_post", - "subject_post_interaction", - "subject_identity", - "subject_identity__domain", - ) - .prefetch_related( - "subject_post__emojis", - ) - .aget(pk=self.pk) - ) diff --git a/activities/models/post.py b/activities/models/post.py index 83c91c1..f6ae6e8 100644 --- a/activities/models/post.py +++ b/activities/models/post.py @@ -447,18 +447,6 @@ class Post(StatorModel): "replies": self.stats.get("replies", 0) if self.stats else 0, } - ### Async helpers ### - - async def afetch_full(self) -> "Post": - """ - Returns a version of the object with all relations pre-loaded - """ - return ( - await Post.objects.select_related("author", "author__domain") - .prefetch_related("mentions", "mentions__domain", "attachments", "emojis") - .aget(pk=self.pk) - ) - ### Local creation/editing ### @classmethod diff --git a/activities/models/post_interaction.py b/activities/models/post_interaction.py index b3ba3a6..13ea824 100644 --- a/activities/models/post_interaction.py +++ b/activities/models/post_interaction.py @@ -27,103 +27,89 @@ class PostInteractionStates(StateGraph): return [cls.new, cls.fanned_out] @classmethod - async def handle_new(cls, instance: "PostInteraction"): + def handle_new(cls, instance: "PostInteraction"): """ Creates all needed fan-out objects for a new PostInteraction. """ - interaction = await instance.afetch_full() # Boost: send a copy to all people who follow this user (limiting # to just local follows if it's a remote boost) # Pin: send Add activity to all people who follow this user - if ( - interaction.type == interaction.Types.boost - or interaction.type == interaction.Types.pin - ): - for target in await interaction.aget_targets(): - await FanOut.objects.acreate( + if instance.type == instance.Types.boost or instance.type == instance.Types.pin: + for target in instance.get_targets(): + FanOut.objects.create( type=FanOut.Types.interaction, identity=target, - subject_post=interaction.post, - subject_post_interaction=interaction, + subject_post=instance.post, + subject_post_interaction=instance, ) # Like: send a copy to the original post author only, # if the liker is local or they are - elif interaction.type == interaction.Types.like: - if interaction.identity.local or interaction.post.local: - await FanOut.objects.acreate( + elif instance.type == instance.Types.like: + if instance.identity.local or instance.post.local: + FanOut.objects.create( type=FanOut.Types.interaction, - identity_id=interaction.post.author_id, - subject_post=interaction.post, - subject_post_interaction=interaction, + identity_id=instance.post.author_id, + subject_post=instance.post, + subject_post_interaction=instance, ) # Vote: send a copy of the vote to the original # post author only if it's a local interaction # to a non local post - elif interaction.type == interaction.Types.vote: - if interaction.identity.local and not interaction.post.local: - await FanOut.objects.acreate( + elif instance.type == instance.Types.vote: + if instance.identity.local and not instance.post.local: + FanOut.objects.create( type=FanOut.Types.interaction, - identity_id=interaction.post.author_id, - subject_post=interaction.post, - subject_post_interaction=interaction, + identity_id=instance.post.author_id, + subject_post=instance.post, + subject_post_interaction=instance, ) else: raise ValueError("Cannot fan out unknown type") # And one for themselves if they're local and it's a boost - if ( - interaction.type == PostInteraction.Types.boost - and interaction.identity.local - ): - await FanOut.objects.acreate( - identity_id=interaction.identity_id, + if instance.type == PostInteraction.Types.boost and instance.identity.local: + FanOut.objects.create( + identity_id=instance.identity_id, type=FanOut.Types.interaction, - subject_post=interaction.post, - subject_post_interaction=interaction, + subject_post=instance.post, + subject_post_interaction=instance, ) return cls.fanned_out @classmethod - async def handle_undone(cls, instance: "PostInteraction"): + def handle_undone(cls, instance: "PostInteraction"): """ Creates all needed fan-out objects to undo a PostInteraction. """ - interaction = await instance.afetch_full() # Undo Boost: send a copy to all people who follow this user # Undo Pin: send a Remove activity to all people who follow this user - if ( - interaction.type == interaction.Types.boost - or interaction.type == interaction.Types.pin - ): - async for follow in interaction.identity.inbound_follows.select_related( + if instance.type == instance.Types.boost or instance.type == instance.Types.pin: + for follow in instance.identity.inbound_follows.select_related( "source", "target" ): if follow.source.local or follow.target.local: - await FanOut.objects.acreate( + FanOut.objects.create( type=FanOut.Types.undo_interaction, identity_id=follow.source_id, - subject_post=interaction.post, - subject_post_interaction=interaction, + subject_post=instance.post, + subject_post_interaction=instance, ) # Undo Like: send a copy to the original post author only - elif interaction.type == interaction.Types.like: - await FanOut.objects.acreate( + elif instance.type == instance.Types.like: + FanOut.objects.create( type=FanOut.Types.undo_interaction, - identity_id=interaction.post.author_id, - subject_post=interaction.post, - subject_post_interaction=interaction, + identity_id=instance.post.author_id, + subject_post=instance.post, + subject_post_interaction=instance, ) else: raise ValueError("Cannot fan out unknown type") # And one for themselves if they're local and it's a boost - if ( - interaction.type == PostInteraction.Types.boost - and interaction.identity.local - ): - await FanOut.objects.acreate( - identity_id=interaction.identity_id, + if instance.type == PostInteraction.Types.boost and instance.identity.local: + FanOut.objects.create( + identity_id=instance.identity_id, type=FanOut.Types.undo_interaction, - subject_post=interaction.post, - subject_post_interaction=interaction, + subject_post=instance.post, + subject_post_interaction=instance, ) return cls.undone_fanned_out @@ -212,17 +198,7 @@ class PostInteraction(StatorModel): [e.subject_post for e in events if e.subject_post], identity ) - ### Async helpers ### - - async def afetch_full(self): - """ - Returns a version of the object with all relations pre-loaded - """ - return await PostInteraction.objects.select_related( - "identity", "post", "post__author" - ).aget(pk=self.pk) - - async def aget_targets(self) -> Iterable[Identity]: + def get_targets(self) -> Iterable[Identity]: """ Returns an iterable with Identities of followers that have unique shared_inbox among each other to be used as target. @@ -237,13 +213,15 @@ class PostInteraction(StatorModel): # Include all followers that are following the boosts if self.type == self.Types.boost: query = query.filter(boosts=True) - async for follow in query.select_related("source"): + for follow in query.select_related("source"): targets.add(follow.source) # Fetch the full blocks and remove them as targets - async for block in self.identity.outbound_blocks.active().filter( - mute=False - ).select_related("target"): + for block in ( + self.identity.outbound_blocks.active() + .filter(mute=False) + .select_related("target") + ): try: targets.remove(block.target) except KeyError: diff --git a/api/models/token.py b/api/models/token.py index 7c0c891..1ab12bd 100644 --- a/api/models/token.py +++ b/api/models/token.py @@ -16,7 +16,6 @@ class PushSubscriptionSchema(BaseModel): keys: Keys alerts: dict[str, bool] policy: str - server_key: str class Token(models.Model): diff --git a/api/schemas.py b/api/schemas.py index e82ff34..0f0441c 100644 --- a/api/schemas.py +++ b/api/schemas.py @@ -498,7 +498,7 @@ class PushSubscription(Schema): value = token.push_subscription if value: value["id"] = "1" - value["server_key"] = settings.VAPID_PUBLIC_KEY + value["server_key"] = settings.SETUP.VAPID_PUBLIC_KEY del value["keys"] return value else: diff --git a/core/models/config.py b/core/models/config.py index 544478b..5dbff44 100644 --- a/core/models/config.py +++ b/core/models/config.py @@ -2,7 +2,6 @@ from functools import partial from typing import ClassVar import pydantic -from asgiref.sync import sync_to_async from django.core.files import File from django.db import models from django.utils.functional import lazy @@ -97,16 +96,6 @@ class Config(models.Model): {"identity__isnull": True, "user__isnull": True, "domain__isnull": True}, ) - @classmethod - async def aload_system(cls): - """ - Async loads the system config options object - """ - return await sync_to_async(cls.load_values)( - cls.SystemOptions, - {"identity__isnull": True, "user__isnull": True, "domain__isnull": True}, - ) - @classmethod def load_user(cls, user): """ @@ -117,16 +106,6 @@ class Config(models.Model): {"identity__isnull": True, "user": user, "domain__isnull": True}, ) - @classmethod - async def aload_user(cls, user): - """ - Async loads the user config options object - """ - return await sync_to_async(cls.load_values)( - cls.UserOptions, - {"identity__isnull": True, "user": user, "domain__isnull": True}, - ) - @classmethod def load_identity(cls, identity): """ @@ -137,16 +116,6 @@ class Config(models.Model): {"identity": identity, "user__isnull": True, "domain__isnull": True}, ) - @classmethod - async def aload_identity(cls, identity): - """ - Async loads an identity config options object - """ - return await sync_to_async(cls.load_values)( - cls.IdentityOptions, - {"identity": identity, "user__isnull": True, "domain__isnull": True}, - ) - @classmethod def load_domain(cls, domain): """ @@ -157,16 +126,6 @@ class Config(models.Model): {"domain": domain, "user__isnull": True, "identity__isnull": True}, ) - @classmethod - async def aload_domain(cls, domain): - """ - Async loads an domain config options object - """ - return await sync_to_async(cls.load_values)( - cls.DomainOptions, - {"domain": domain, "user__isnull": True, "identity__isnull": True}, - ) - @classmethod def set_value(cls, key, value, options_class, filters): config_field = options_class.__fields__[key] diff --git a/stator/management/commands/runstator.py b/stator/management/commands/runstator.py index cf09333..acef21b 100644 --- a/stator/management/commands/runstator.py +++ b/stator/management/commands/runstator.py @@ -16,7 +16,7 @@ class Command(BaseCommand): "--concurrency", "-c", type=int, - default=30, + default=15, help="How many tasks to run at once", ) parser.add_argument( diff --git a/stator/views.py b/stator/views.py index df51e3d..90fc0e1 100644 --- a/stator/views.py +++ b/stator/views.py @@ -12,7 +12,7 @@ class RequestRunner(View): For when you're on something serverless. """ - async def get(self, request): + def get(self, request): # Check the token, if supplied if not settings.STATOR_TOKEN: return HttpResponseForbidden("No token set") @@ -20,5 +20,5 @@ class RequestRunner(View): return HttpResponseForbidden("Invalid token") # Run on all models runner = StatorRunner(StatorModel.subclasses, run_for=2) - handled = await runner.run() + handled = runner.run() return HttpResponse(f"Handled {handled}") diff --git a/users/models/block.py b/users/models/block.py index e9280d6..1871ab4 100644 --- a/users/models/block.py +++ b/users/models/block.py @@ -58,7 +58,7 @@ class BlockStates(StateGraph): return cls.sent @classmethod - async def handle_awaiting_expiry(cls, instance: "Block"): + def handle_awaiting_expiry(cls, instance: "Block"): """ Checks to see if there is an expiry we should undo """ diff --git a/users/models/follow.py b/users/models/follow.py index a9b6063..b9f1fde 100644 --- a/users/models/follow.py +++ b/users/models/follow.py @@ -60,7 +60,7 @@ class FollowStates(StateGraph): return cls.local_requested @classmethod - async def handle_local_requested(cls, instance: "Follow"): + def handle_local_requested(cls, instance: "Follow"): # TODO: Resend follow requests occasionally pass diff --git a/users/models/identity.py b/users/models/identity.py index 92c3d4f..2b9adfc 100644 --- a/users/models/identity.py +++ b/users/models/identity.py @@ -119,7 +119,7 @@ class IdentityStates(StateGraph): return cls.updated @classmethod - async def handle_updated(cls, instance: "Identity"): + def handle_updated(cls, instance: "Identity"): if instance.state_age > Config.system.identity_max_age: return cls.outdated diff --git a/users/models/password_reset.py b/users/models/password_reset.py index 90c61fd..4f36012 100644 --- a/users/models/password_reset.py +++ b/users/models/password_reset.py @@ -1,7 +1,6 @@ import random import string -from asgiref.sync import sync_to_async from django.conf import settings from django.core.mail import send_mail from django.db import models @@ -18,18 +17,17 @@ class PasswordResetStates(StateGraph): new.transitions_to(sent) @classmethod - async def handle_new(cls, instance: "PasswordReset"): + def handle_new(cls, instance: "PasswordReset"): """ Sends the password reset email. """ - reset = await instance.afetch_full() - if reset.new_account: - await sync_to_async(send_mail)( + if instance.new_account: + send_mail( subject=f"{Config.system.site_name}: Confirm new account", message=render_to_string( "emails/account_new.txt", { - "reset": reset, + "reset": instance, "config": Config.system, "settings": settings, }, @@ -37,21 +35,21 @@ class PasswordResetStates(StateGraph): html_message=render_to_string( "emails/account_new.html", { - "reset": reset, + "reset": instance, "config": Config.system, "settings": settings, }, ), from_email=settings.SERVER_EMAIL, - recipient_list=[reset.user.email], + recipient_list=[instance.user.email], ) else: - await sync_to_async(send_mail)( + send_mail( subject=f"{Config.system.site_name}: Reset password", message=render_to_string( "emails/password_reset.txt", { - "reset": reset, + "reset": instance, "config": Config.system, "settings": settings, }, @@ -59,13 +57,13 @@ class PasswordResetStates(StateGraph): html_message=render_to_string( "emails/password_reset.html", { - "reset": reset, + "reset": instance, "config": Config.system, "settings": settings, }, ), from_email=settings.SERVER_EMAIL, - recipient_list=[reset.user.email], + recipient_list=[instance.user.email], ) return cls.sent @@ -96,13 +94,3 @@ class PasswordReset(StatorModel): token="".join(random.choice(string.ascii_lowercase) for i in range(42)), new_account=not user.password, ) - - ### Async helpers ### - - async def afetch_full(self): - """ - Returns a version of the object with all relations pre-loaded - """ - return await PasswordReset.objects.select_related( - "user", - ).aget(pk=self.pk)