Loads of rewriting of sombrero's "deliver" function so it works with the new model. It still needs more work, but this is an intermediate checkin.

OutgoingActivity model added to sombrero.

sombrero gains a "receivers" file so it can respond to follows etc.

Fetch model deleted from bowler, though I think it'll need to reappear in sombrero soon.
trilby-heavy
Marnanel Thurman 2020-05-06 20:03:11 +01:00
rodzic 5e29730370
commit 2e77df6454
6 zmienionych plików z 169 dodań i 76 usunięć

Wyświetl plik

@ -0,0 +1,16 @@
# Generated by Django 3.0.4 on 2020-05-06 18:41
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('bowler_pub', '0001_initial'),
]
operations = [
migrations.DeleteModel(
name='Fetch',
),
]

Wyświetl plik

@ -0,0 +1 @@
import kepi.sombrero_sendpub.receivers

Wyświetl plik

@ -9,23 +9,28 @@ This module contains deliver(), which delivers objects
to their audiences.
"""
from __future__ import absolute_import, unicode_literals
from celery import shared_task
from kepi.bowler_pub.utils import is_local
import kepi.bowler_pub.models
from httpsig.verify import HeaderVerifier
from urllib.parse import urlparse
from django.http.request import HttpRequest
from django.conf import settings
import django.urls
import django.utils.datastructures
import logging
import requests
import json
import httpsig
import random
from django.http.request import HttpRequest
from django.conf import settings
from kepi.bowler_pub.utils import configured_url, as_json, is_local
"""
from __future__ import absolute_import, unicode_literals
from kepi.bowler_pub.utils import is_local
import kepi.bowler_pub.models
from urllib.parse import urlparse
import django.urls
import django.utils.datastructures
import datetime
import pytz
import httpsig
from httpsig.verify import HeaderVerifier
from collections.abc import Iterable
""" # FIXME
logger = logging.getLogger(name='kepi')
@ -88,6 +93,8 @@ def _recipients_to_inboxes(recipients,
there will be no duplicates.
"""
from kepi.bowler_pub import PUBLIC_IDS
logger.info('Looking up inboxes for: %s',
recipients)
@ -397,93 +404,69 @@ def _deliver_remote(
@shared_task()
def deliver(
activity_id,
incoming = False,
activity,
):
"""
Deliver an activity to an actor.
Keyword arguments:
activity_id -- the "id" field of an Activity
incoming -- True if we just received this, False otherwise
activity -- a dict representing an ActivityPub activity.
This function is a shared task; it will be run by Celery behind
the scenes.
"""
try:
activity = kepi.bowler_pub.models.AcActivity.objects.get(id=activity_id)
except kepi.bowler_pub.models.AcActivity.DoesNotExist:
logger.warn("Can't deliver activity %s because it doesn't exist",
activity_id)
return None
import kepi.sombrero_sendpub.models as sombrero_models
from kepi.bowler_pub import PUBLIC_IDS
logger.info('%s: begin delivery; incoming==%s',
activity, incoming)
message = sombrero_models.OutgoingActivity(
content=activity,
)
message.save()
activity_form = activity.activity_form
logger.debug('%s: full form is %s',
activity, activity_form)
local_actor = _find_local_actor(activity_form)
logger.debug('%s: local actor is %s',
activity, local_actor)
logger.info('activity %d: begin delivery: %s',
message.pk, message.content)
recipients = set()
for field in ['to', 'bto', 'cc', 'bcc', 'audience']:
if field in activity_form:
recipients.update(activity_form[field])
if local_actor is not None:
if incoming:
# Actors don't get told about their own (incoming) activities
if local_actor.url in recipients:
logger.info(' -- removing actor from recipients')
recipients.remove(local_actor.url)
else:
# but if it originated locally, the status should appear in the
# actor's own inbox too
if local_actor.url not in recipients:
logger.info(' -- adding actor to recipients')
recipients.add(local_actor.url)
if field in activity:
for recipient in activity[field]:
if not is_local(recipient):
recipients.update(activity[field])
if not recipients:
logger.debug('%s: there are no recipients; giving up',
activity)
logger.debug('activity %d: there are no recipients; giving up',
message.pk)
return
logger.debug('%s: recipients are %s',
logger.debug('activity %d: recipients are %s',
activity, recipients)
if incoming:
# Dereference collections.
inboxes = recipients
message = ''
signer = None
inboxes = _recipients_to_inboxes(recipients,
local_actor=activity['actor'])
else:
if not inboxes:
logger.debug('activity %s: there are no inboxes to send to; giving up',
message.pk)
return
# Dereference collections.
logger.debug('%s: inboxes are %s',
activity, inboxes)
inboxes = _recipients_to_inboxes(recipients,
local_actor=local_actor)
############################
raise ValueError("XXX TO HERE") # XXX TO HERE
############################
if not inboxes:
logger.debug('%s: there are no inboxes to send to; giving up',
activity)
return
message = _activity_form_to_outgoing_string(
activity_form = activity_form,
)
logger.debug('%s: inboxes are %s',
activity, inboxes)
message = _activity_form_to_outgoing_string(
activity_form = activity_form,
)
signer = _signer_for_local_actor(
local_actor = local_actor,
)
signer = _signer_for_local_actor(
local_actor = local_actor,
)
for inbox in inboxes:
logger.debug('%s: %s: begin delivery',
@ -497,12 +480,7 @@ def deliver(
logger.debug(" -- mustn't deliver to Public")
continue
parsed_target_url = urlparse(inbox,
allow_fragments = False,
)
is_local = parsed_target_url.hostname in settings.ALLOWED_HOSTS
if is_local:
if is_local(inbox):
_deliver_local(
activity,
inbox,

Wyświetl plik

@ -0,0 +1,21 @@
# Generated by Django 3.0.4 on 2020-05-06 18:41
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='OutgoingActivity',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('content', models.TextField()),
],
),
]

Wyświetl plik

@ -1,3 +1,49 @@
from django.db import models
from kepi.bowler_pub.utils import configured_url, as_json
import json
# Create your models here.
class OutgoingActivity(models.Model):
content = models.TextField()
@property
def url(self):
return configured_url(
'ACTIVITY_LINK',
serial = self.pk,
)
@property
def value(self):
result = json.loads(self.content)
if not isinstance(result['to'], list):
result['to'] = [result['to']]
if 'id' not in result:
result['id'] = self.url
if '@context' not in result:
from kepi.bowler_pub import ATSIGN_CONTEXT
result['@context'] = ATSIGN_CONTEXT
return result
def __repr__(self):
return as_json(self.value)
def __str__(self):
return self.__repr__()
def save(self, *args, **kwargs):
if not isinstance(self.content, str):
for field in ['type', 'actor', 'to']:
if field not in self.content:
raise ValueError("activity is missing required fields: %s",
self.content)
self.content = json.dumps(self.content)
super().save(*args, **kwargs)

Wyświetl plik

@ -0,0 +1,31 @@
import kepi.trilby_api.signals as kepi_signals
from django.dispatch import receiver
from kepi.sombrero_sendpub.delivery import deliver
import logging
logger = logging.Logger("kepi")
@receiver(kepi_signals.followed)
def on_follow(sender, **kwargs):
"""
If the Follow event describes a remote person being followed,
then send them an ActivityPub "Follow" activity message about it.
The spec for "Follow" is here:
https://www.w3.org/TR/activitystreams-vocabulary/#dfn-follow
"""
if sender.following.is_local:
logger.debug("%s is local; not sending update", sender)
return
print("Follow received:", sender)
logger.info("Follow received: %s", sender)
deliver(
activity = {
'type': 'Follow',
'actor': sender.follower.url,
'object': sender.following.url,
'to': sender.following.url,
},
)