aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorwinter2024-12-19 22:59:40 +0000
committerwinter2024-12-19 22:59:40 +0000
commitdf051a7524a93f96bfc69924c202a51286517ce2 (patch)
treeae6818812367b642e5359291f04b47a6627c02e8
parentf6a55426cac40501aa7f8e88eb7bfd318d7cd170 (diff)
let notes push themselves to interested parties
-rw-r--r--Digitigrade/Job/PushObject.php30
-rw-r--r--Digitigrade/Model/Actor.php39
-rw-r--r--Digitigrade/Model/FollowRelation.php14
-rw-r--r--Digitigrade/Model/Note.php27
-rw-r--r--Digitigrade/Model/PushableModel.php3
5 files changed, 113 insertions, 0 deletions
diff --git a/Digitigrade/Job/PushObject.php b/Digitigrade/Job/PushObject.php
new file mode 100644
index 0000000..f5f1430
--- /dev/null
+++ b/Digitigrade/Job/PushObject.php
@@ -0,0 +1,30 @@
+<?php
+namespace Digitigrade\Job;
+
+use Digitigrade\Job;
+use Digitigrade\Logger;
+use Digitigrade\Model\Instance;
+use Digitigrade\Model\PushableModel;
+
+class PushObject extends Job {
+ public string $objectType;
+ public string $objectId;
+ public string $recipientServerHost;
+
+ public function __construct(PushableModel $object, Instance $recipient) {
+ $this->objectType = $object::class;
+ $this->objectId = $object->id;
+ $this->recipientServerHost = $recipient->domain;
+ $this->remainingTries = 8;
+ }
+
+ public function run() {
+ $instance = Instance::findByHostname($this->recipientServerHost);
+ assert($instance != null);
+ $object = $this->objectType::find($this->objectId);
+ assert($object instanceof PushableModel);
+
+ Logger::getInstance()->info("pushing object $object->uri to server $instance->domain");
+ $instance->pushObject($object);
+ }
+} \ No newline at end of file
diff --git a/Digitigrade/Model/Actor.php b/Digitigrade/Model/Actor.php
index e419ef6..89f4d50 100644
--- a/Digitigrade/Model/Actor.php
+++ b/Digitigrade/Model/Actor.php
@@ -145,6 +145,45 @@ class Actor extends PushableModel implements RpcReceiver {
$target->rpcCall('unfollow', [$this]);
}
+ /**
+ * @return Actor[] a list of actors that follow this actor (does not include pending follows)
+ */
+ public function findFollowers(): array {
+ $relations = FollowRelation::findAllWithObject($this);
+ $relations = array_filter($relations, function (FollowRelation $rel) {
+ return $rel->status == FollowRelationStatus::ACTIVE;
+ });
+ return array_map(function (FollowRelation $rel) {
+ return $rel->subject;
+ }, $relations);
+ }
+
+ /**
+ * @return Actor[] a list of actors that are followed by this actor (does not include pending follows)
+ */
+ public function findFollowees(): array {
+ $relations = FollowRelation::findAllWithSubject($this);
+ $relations = array_filter($relations, function (FollowRelation $rel) {
+ return $rel->status == FollowRelationStatus::ACTIVE;
+ });
+ return array_map(function (FollowRelation $rel) {
+ return $rel->object;
+ }, $relations);
+ }
+
+ /**
+ * @return Actor[] a list of actors that both follow and are followed by this actor
+ */
+ public function findMutualFollows(): array {
+ $followers = $this->findFollowers();
+ $followees = $this->findFollowees();
+ return array_intersect($followers, $followees);
+ }
+
+ public function findHomeInstance(): Instance {
+ return Instance::findByHostname(hostname_from_uri($this->uri));
+ }
+
public function jsonSerialize(): array {
return [
'type' => 'actor',
diff --git a/Digitigrade/Model/FollowRelation.php b/Digitigrade/Model/FollowRelation.php
index fc43a6f..0af9da5 100644
--- a/Digitigrade/Model/FollowRelation.php
+++ b/Digitigrade/Model/FollowRelation.php
@@ -34,4 +34,18 @@ class FollowRelation extends Model {
public static function findByActors(Actor $subject, Actor $object): ?self {
return self::findWhere('subject = ? and object = ?', [$subject->id, $object->id]);
}
+
+ /**
+ * @return self[]
+ */
+ public static function findAllWithSubject(Actor $subject): array {
+ return self::findAllWhere('subject = ?', [$subject->id]);
+ }
+
+ /**
+ * @return self[]
+ */
+ public static function findAllWithObject(Actor $object): array {
+ return self::findAllWhere('object = ?', [$object->id]);
+ }
} \ No newline at end of file
diff --git a/Digitigrade/Model/Note.php b/Digitigrade/Model/Note.php
index 0117a3c..7ffb67e 100644
--- a/Digitigrade/Model/Note.php
+++ b/Digitigrade/Model/Note.php
@@ -2,6 +2,7 @@
namespace Digitigrade\Model;
use Digitigrade\Db;
+use Digitigrade\Job\PushObject;
class Note extends PushableModel {
public ?int $id;
@@ -109,6 +110,32 @@ class Note extends PushableModel {
return Interaction::findAllWithTarget($this);
}
+ /**
+ * Sends this note to all instances it's relevant to.
+ *
+ * For example, this may include the servers of any followers if the scope is at
+ * least 'followers', anyone mentioned, and anyone in the alsoVisibleTo field.
+ * If the scope is 'public' it may also send it to other servers? i'm not sure
+ * @return void
+ */
+ public function publish() {
+ $recipientActors = match ($this->privacy->scope) {
+ NotePrivacyScope::NONE => [],
+ NotePrivacyScope::MUTUALS => $this->author->findMutualFollows(),
+ default => $this->author->findFollowers()
+ };
+ $recipientActors = array_merge($recipientActors, $this->mentions, $this->privacy->alsoVisibleTo);
+ $recipientActors = array_unique($recipientActors);
+ $instances = array_map(function (Actor $a) {
+ return $a->findHomeInstance();
+ }, $recipientActors);
+ $instances = array_unique($instances);
+
+ foreach ($instances as $instance) {
+ (new PushObject($this, $instance))->submit();
+ }
+ }
+
public function jsonSerialize(): array {
return [
'type' => 'note',
diff --git a/Digitigrade/Model/PushableModel.php b/Digitigrade/Model/PushableModel.php
index 21415f7..c008320 100644
--- a/Digitigrade/Model/PushableModel.php
+++ b/Digitigrade/Model/PushableModel.php
@@ -2,6 +2,9 @@
namespace Digitigrade\Model;
abstract class PushableModel extends FetchableModel implements \JsonSerializable {
+ public ?int $id;
+ public string $uri;
+
public static function importFromReceivedObject(\stdClass $data, bool $autoSave = true): static {
$obj = static::createFromJson($data, $autoSave);
if ($autoSave) {