From 72b07245f44c73ed41bfcca2465a9ee34426a922 Mon Sep 17 00:00:00 2001 From: winter Date: Thu, 19 Dec 2024 20:59:18 +0000 Subject: implement follow relationships (untested) does NOT implement the actual behaviour behind follows (receiving posts and such) --- Digitigrade/Model/Actor.php | 67 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 2 deletions(-) (limited to 'Digitigrade/Model/Actor.php') 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 @@ 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"), ] ]; } -- cgit v1.3