aboutsummaryrefslogtreecommitdiffhomepage
path: root/Digitigrade/Model/Actor.php
diff options
context:
space:
mode:
authorwinter2024-12-19 20:59:18 +0000
committerwinter2024-12-19 20:59:18 +0000
commit72b07245f44c73ed41bfcca2465a9ee34426a922 (patch)
tree57372703100ad792c95c665a568aabe8a763bfdf /Digitigrade/Model/Actor.php
parent1e070a7a0097c74f8ac30678d39267f19c76f9f6 (diff)
implement follow relationships (untested)
does NOT implement the actual behaviour behind follows (receiving posts and such)
Diffstat (limited to 'Digitigrade/Model/Actor.php')
-rw-r--r--Digitigrade/Model/Actor.php67
1 files changed, 65 insertions, 2 deletions
diff --git a/Digitigrade/Model/Actor.php b/Digitigrade/Model/Actor.php
index 4f3aab2..fa08463 100644
--- a/Digitigrade/Model/Actor.php
+++ b/Digitigrade/Model/Actor.php
@@ -1,7 +1,10 @@
<?php
namespace Digitigrade\Model;
-class Actor extends PushableModel {
+use Digitigrade\RpcException;
+use Digitigrade\RpcReceiver;
+
+class Actor extends PushableModel implements RpcReceiver {
public ?int $id;
public string $uri;
public bool $isLocal = false;
@@ -83,6 +86,64 @@ class Actor extends PushableModel {
return ActorWebfinger::findByAcct($acct, $autoSave, $forceRefetch)->actor;
}
+ public static function findByRequestHeaders(): ?self {
+ $instance = Instance::findByRequestHeaders();
+ if ($instance == null || !isset($_SERVER['HTTP_X_PAWPUB_ACTOR']))
+ return null;
+ $uri = $_SERVER['HTTP_X_PAWPUB_ACTOR'];
+ if (hostname_from_uri($uri) != $instance->domain)
+ return null;
+ return self::findByUri($uri);
+ }
+
+ protected function rpcCall(string $method, array $args) {
+ switch ($method) {
+ case 'follow': // $this is the target, $args[0] is the initiator
+ $status = $this->requestToFollow ? FollowRelationStatus::PENDING : FollowRelationStatus::ACTIVE;
+ if (!$this->isLocal) {
+ $endpoint = $this->endpoints->follow ?? null;
+ if (!isset($endpoint, $this->endpoints->unfollow)) {
+ throw new RpcException("Actor `$this->uri` has no (un)follow endpoint");
+ }
+ $result = send_request_authenticated($endpoint, method: 'POST', actingAs: $args[0]);
+ if (!str_contains($result->headers[0], ' 20')) {
+ throw new RpcException('remote call did not indicate success: ' . $result->headers[0]);
+ }
+ }
+ FollowRelation::create($args[0], $this, $status);
+ return $status;
+
+ case 'unfollow':
+ if (!$this->isLocal) {
+ $endpoint = $this->endpoints->unfollow ?? null;
+ if (!isset($endpoint, $this->endpoints->follow)) {
+ throw new RpcException("Actor `$this->uri` has no (un)follow endpoint");
+ }
+ $result = send_request_authenticated($endpoint, method: 'POST', actingAs: $args[0]);
+ if (!str_contains($result->headers[0], ' 20')) {
+ throw new RpcException('remote call did not indicate success: ' . $result->headers[0]);
+ }
+ }
+ FollowRelation::findByActors($args[0], $this)->remove();
+
+ default:
+ throw new \RuntimeException("Actor rpc method $method not (yet?) implemented");
+ }
+ }
+
+ /**
+ * Tries to follow (or send a follow request to) another actor
+ * @param Actor $target the actor to follow
+ * @return FollowRelationStatus PENDING if a request was sent or ACTIVE if the follow went through immediately
+ */
+ public function follow(self $target): FollowRelationStatus {
+ return $target->rpcCall('follow', [$this]);
+ }
+
+ public function unfollow(self $target) {
+ $target->rpcCall('unfollow', [$this]);
+ }
+
public function jsonSerialize(): array {
return [
'type' => 'actor',
@@ -97,7 +158,9 @@ class Actor extends PushableModel {
'automated' => $this->automated,
'endpoints' => [
'basicFeed' => path_to_uri("/user/$this->handle/basicFeed"),
- 'fullFeed' => path_to_uri("/user/$this->handle/fullFeed")
+ 'fullFeed' => path_to_uri("/user/$this->handle/fullFeed"),
+ 'follow' => path_to_uri("/user/$this->handle/follow"),
+ 'unfollow' => path_to_uri("/user/$this->handle/unfollow"),
]
];
}