From 615fcb2e4518724c6e4585d1608fe0b145872881 Mon Sep 17 00:00:00 2001 From: Jeremy Dormitzer Date: Sun, 28 Apr 2019 16:08:22 -0400 Subject: [PATCH] [WIP] Begin implementing CachingDereferencer --- composer.json | 11 +- .../Dereferencer/CachingDereferencer.php | 160 ++++++++++++++++++ test/JsonLd/JsonLdNodeTest.php | 23 ++- 3 files changed, 184 insertions(+), 10 deletions(-) create mode 100644 src/JsonLd/Dereferencer/CachingDereferencer.php diff --git a/composer.json b/composer.json index 341fa30..87933b6 100644 --- a/composer.json +++ b/composer.json @@ -15,21 +15,17 @@ "test-debug": "XDEBUG_CONFIG='idekey=ap_session' php ./vendor/bin/phpunit test", "docs": "phpdoc -d ./src -t ./docs" }, - "repositories": [ - { - "type": "vcs", - "url": "https://git.friendi.ca/friendica/php-json-ld" - } - ], "require": { "ext-json": "*", + "cache/apc-adapter": "0.3.2", + "cache/apcu-adapter": "0.2.2", + "cache/filesystem-adapter": "0.3.3", "doctrine/annotations": "1.2.7", "doctrine/cache": "1.6.2", "doctrine/collections": "1.3.0", "doctrine/common": "2.6.2", "doctrine/instantiator": "1.0.5", "doctrine/orm": "2.5.14", - "friendica/json-ld": "^1.1", "guzzlehttp/guzzle": "^6.3", "ml/json-ld": "1.1.0", "monolog/monolog": "^1.0", @@ -44,6 +40,7 @@ }, "require-dev": { "ext-pdo": "*", + "cache/array-adapter": "0.4.2", "phpunit/dbunit": "^2.0", "phpunit/phpunit": "^4.0" }, diff --git a/src/JsonLd/Dereferencer/CachingDereferencer.php b/src/JsonLd/Dereferencer/CachingDereferencer.php new file mode 100644 index 0000000..b6e1933 --- /dev/null +++ b/src/JsonLd/Dereferencer/CachingDereferencer.php @@ -0,0 +1,160 @@ +logger = $logger; + $this->cache = $cache; + $this->httpClient = $httpClient; + $this->httpSignatureService = $httpSignatureService; + $this->keyId = $keyId; + $this->privateKey = $privateKey; + } + + public function setKeyId( $keyId ) + { + $this->keyId = $keyId; + } + + public function setPrivateKey( $privateKey ) + { + $this->privateKey = $privateKey; + } + + /** + * @param string $iri The IRI to dereference. + * @return stdClass|array The dereferenced node. + * @throws NodeNotFoundException If a node with the IRI could not be found. + */ + public function dereference( $iri ) + { + $key = $this->makeCacheKey( $iri ); + $cacheItem = $this->cache->getItem( $key ); + if ( $cacheItem->isHit() ) { + return $cacheItem->get(); + } else { + if ( Util::isLocalUri( $iri ) ) { + // TODO fetch object from persistence backend + } + $headers = array( + 'Accept' => 'application/ld+json', + 'Date' => $this->getNowRFC1123(), + ); + $request = new Request( 'GET', $iri, $headers ); + if ( $this->shouldSign() ) { + $signature = $this->httpSignatureService->sign( $request, $this->privateKey, $this->keyId ); + $request = $request->withHeader( 'Signature', $signature ); + } + $response = $this->httpClient->send( $request ); + if ( $response->getStatusCode() >= 400 ) { + $statusCode = $response->getStatusCode(); + $this->logger->error( + "[ActivityPub-PHP] Received response with status $statusCode from $iri", + array( 'request' => $request, 'response' => $response ) + ); + } else { + $body = json_decode( $response->getBody() ); + if ( ! $body ) { + throw new NodeNotFoundException( $iri ); + } + $cacheItem->set( $body ); + $cacheItem->expiresAfter( self::DEFAULT_CACHE_TTL ); + $this->cache->save( $cacheItem ); + return $body; + } + } + } + + /** + * Generates a valid cache key for $id. + * @param string $id + * @return string + */ + private function makeCacheKey( $id ) + { + return str_replace( array( '{', '}', '(', ')', '/', '\\', '@', ':' ), '_', $id ); + } + + /** + * True if the dereferencer should sign outgoing requests. + * @return bool + */ + private function shouldSign() + { + return $this->keyId && $this->privateKey; + } + + private function getNowRFC1123() + { + $now = new DateTime( 'now', new DateTimeZone( 'GMT' ) ); + return $now->format( 'D, d M Y H:i:s T' ); + } +} \ No newline at end of file diff --git a/test/JsonLd/JsonLdNodeTest.php b/test/JsonLd/JsonLdNodeTest.php index d872904..30183b0 100644 --- a/test/JsonLd/JsonLdNodeTest.php +++ b/test/JsonLd/JsonLdNodeTest.php @@ -441,6 +441,21 @@ class JsonLdNodeTest extends APTestCase 'id' => 'https://example.org/articles/1', 'type' => 'Article', ) + ), + array( + new stdClass(), + $this->asContext, + 'to', + array( + (object) array( + 'id' => 'https://example.org/sally', + 'type' => 'Person', + ), + (object) array( + 'id' => 'https://example.org/bob', + 'type' => 'Person', + ) + ), ) ); } @@ -452,9 +467,11 @@ class JsonLdNodeTest extends APTestCase { $parentNode = $this->makeJsonLdNode( $inputObj, $context ); $parentNode->set( $newPropertyName, $newNodeValue ); - $childNode = $parentNode->get( $newPropertyName ); - $this->assertInstanceOf( JsonLdNode::class, $childNode ); - $this->assertEquals( $childNode->getBackReferences( $newPropertyName ), array( $parentNode ) ); + $childNodes = $parentNode->getMany( $newPropertyName ); + foreach ( $childNodes as $childNode ) { + $this->assertInstanceOf( JsonLdNode::class, $childNode ); + $this->assertEquals( $childNode->getBackReferences( $newPropertyName ), array( $parentNode ) ); + } } private function makeJsonLdNode( $inputObj, $context, $nodeGraph = array() )