Force refresh actor once in a while
This commit is contained in:
parent
c8a9793638
commit
f6cfe06f66
2 changed files with 41 additions and 18 deletions
57
app/actor.py
57
app/actor.py
|
@ -1,6 +1,7 @@
|
||||||
import hashlib
|
import hashlib
|
||||||
import typing
|
import typing
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from datetime import timedelta
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
from typing import Union
|
from typing import Union
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
@ -12,6 +13,8 @@ from sqlalchemy.orm import joinedload
|
||||||
from app import activitypub as ap
|
from app import activitypub as ap
|
||||||
from app import media
|
from app import media
|
||||||
from app.database import AsyncSession
|
from app.database import AsyncSession
|
||||||
|
from app.utils.datetime import as_utc
|
||||||
|
from app.utils.datetime import now
|
||||||
|
|
||||||
if typing.TYPE_CHECKING:
|
if typing.TYPE_CHECKING:
|
||||||
from app.models import Actor as ActorModel
|
from app.models import Actor as ActorModel
|
||||||
|
@ -189,26 +192,44 @@ async def fetch_actor(
|
||||||
if existing_actor:
|
if existing_actor:
|
||||||
if existing_actor.is_deleted:
|
if existing_actor.is_deleted:
|
||||||
raise ap.ObjectNotFoundError(f"{actor_id} was deleted")
|
raise ap.ObjectNotFoundError(f"{actor_id} was deleted")
|
||||||
return existing_actor
|
|
||||||
else:
|
|
||||||
if save_if_not_found:
|
|
||||||
ap_actor = await ap.fetch(actor_id)
|
|
||||||
# Some softwares uses URL when we expect ID
|
|
||||||
if actor_id == ap_actor.get("url"):
|
|
||||||
# Which mean we may already have it in DB
|
|
||||||
existing_actor_by_url = (
|
|
||||||
await db_session.scalars(
|
|
||||||
select(models.Actor).where(
|
|
||||||
models.Actor.ap_id == ap.get_id(ap_actor),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
).one_or_none()
|
|
||||||
if existing_actor_by_url:
|
|
||||||
return existing_actor_by_url
|
|
||||||
|
|
||||||
return await save_actor(db_session, ap_actor)
|
if now() - as_utc(existing_actor.updated_at) > timedelta(hours=24):
|
||||||
|
logger.info(
|
||||||
|
f"Refreshing {actor_id=} last updated {existing_actor.updated_at}"
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
ap_actor = await ap.fetch(actor_id)
|
||||||
|
existing_actor.ap_actor = ap_actor
|
||||||
|
existing_actor.updated_at = now()
|
||||||
|
return existing_actor
|
||||||
|
except Exception:
|
||||||
|
logger.exception(f"Failed to refresh {actor_id}")
|
||||||
|
# If we fail to refresh the actor, return the cached one
|
||||||
|
return existing_actor
|
||||||
else:
|
else:
|
||||||
raise ap.ObjectNotFoundError(actor_id)
|
return existing_actor
|
||||||
|
|
||||||
|
if save_if_not_found:
|
||||||
|
ap_actor = await ap.fetch(actor_id)
|
||||||
|
# Some softwares uses URL when we expect ID
|
||||||
|
if actor_id == ap_actor.get("url"):
|
||||||
|
# Which mean we may already have it in DB
|
||||||
|
existing_actor_by_url = (
|
||||||
|
await db_session.scalars(
|
||||||
|
select(models.Actor).where(
|
||||||
|
models.Actor.ap_id == ap.get_id(ap_actor),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).one_or_none()
|
||||||
|
if existing_actor_by_url:
|
||||||
|
# Update the actor as we had to fetch it anyway
|
||||||
|
existing_actor_by_url.ap_actor = ap_actor
|
||||||
|
existing_actor_by_url.updated_at = now()
|
||||||
|
return existing_actor_by_url
|
||||||
|
|
||||||
|
return await save_actor(db_session, ap_actor)
|
||||||
|
else:
|
||||||
|
raise ap.ObjectNotFoundError(actor_id)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
|
@ -1492,6 +1492,7 @@ async def _handle_update_activity(
|
||||||
|
|
||||||
# Update the actor
|
# Update the actor
|
||||||
from_actor.ap_actor = updated_actor.ap_actor
|
from_actor.ap_actor = updated_actor.ap_actor
|
||||||
|
from_actor.updated_at = now()
|
||||||
elif (ap_type := wrapped_object["type"]) in [
|
elif (ap_type := wrapped_object["type"]) in [
|
||||||
"Question",
|
"Question",
|
||||||
"Note",
|
"Note",
|
||||||
|
@ -1514,6 +1515,7 @@ async def _handle_update_activity(
|
||||||
# Everything looks correct, update the object in the inbox
|
# Everything looks correct, update the object in the inbox
|
||||||
logger.info(f"Updating {existing_object.ap_id}")
|
logger.info(f"Updating {existing_object.ap_id}")
|
||||||
existing_object.ap_object = wrapped_object
|
existing_object.ap_object = wrapped_object
|
||||||
|
existing_object.updated_at = now()
|
||||||
else:
|
else:
|
||||||
# TODO(ts): support updating objects
|
# TODO(ts): support updating objects
|
||||||
logger.info(f'Cannot update {wrapped_object["type"]}')
|
logger.info(f'Cannot update {wrapped_object["type"]}')
|
||||||
|
|
Loading…
Reference in a new issue