Skip to content

Commit

Permalink
use StreamedResponse in packages() controller method
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeroeny committed Sep 7, 2022
1 parent 50fe808 commit 8a07cf6
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 125 deletions.
75 changes: 47 additions & 28 deletions src/Controller/RepoController.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;

final class RepoController extends AbstractController
{
Expand All @@ -41,32 +41,42 @@ public function __construct(
* @Route("/packages.json", host="{organization}{sep1}repo{sep2}{domain}", name="repo_packages", methods={"GET"}, defaults={"domain":"%domain%","sep1"="%organization_separator%","sep2"="%domain_separator%"}, requirements={"domain"="%domain%","sep1"="%organization_separator%","sep2"="%domain_separator%"})
* @Cache(public=false)
*/
public function packages(Request $request, Organization $organization): JsonResponse
public function packages(Request $request, Organization $organization): Response
{
$packageNames = $this->packageQuery->getAllNames($organization->id());
[$lastModified, $packages] = $this->packageManager->findProviders($organization->alias(), $packageNames);

$response = (new JsonResponse([
'packages' => $packages,
'available-packages' => array_map(static fn (PackageName $packageName) => $packageName->name(), $packageNames),
'metadata-url' => '/p2/%package%.json',
'notify-batch' => $this->generateUrl('repo_package_downloads', [
'organization' => $organization->alias(),
], UrlGeneratorInterface::ABSOLUTE_URL),
'search' => 'https://packagist.org/search.json?q=%query%&type=%type%',
'mirrors' => [
[
'dist-url' => $this->generateUrl(
'organization_repo_url',
['organization' => $organization->alias()],
RouterInterface::ABSOLUTE_URL
).'dists/%package%/%version%/%reference%.%type%',
'preferred' => true,
[$lastModified, $loader] = $this->packageManager->findProviders($organization->alias(), $packageNames);

$response = (new StreamedResponse(function () use ($organization, $packageNames, $loader): void {
$outputStream = \fopen('php://output', 'wb');
if (false === $outputStream) {
throw new HttpException(500, 'Could not open output stream to send binary file.'); // @codeCoverageIgnore
}

\fwrite($outputStream, ' ');
\flush();
\fwrite($outputStream, (string) \json_encode([
'packages' => $loader(),
'available-packages' => array_map(static fn (PackageName $packageName) => $packageName->name(), $packageNames),
'metadata-url' => '/p2/%package%.json',
'providers-url' => '/p2/%package%.json',
'notify-batch' => $this->generateUrl('repo_package_downloads', [
'organization' => $organization->alias(),
], UrlGeneratorInterface::ABSOLUTE_URL),
'search' => 'https://packagist.org/search.json?q=%query%&type=%type%',
'mirrors' => [
[
'dist-url' => $this->generateUrl(
'organization_repo_url',
['organization' => $organization->alias()],
UrlGeneratorInterface::ABSOLUTE_URL
).'dists/%package%/%version%/%reference%.%type%',
'preferred' => true,
],
],
],
]))
->setPrivate()
->setLastModified($lastModified);
], JsonResponse::DEFAULT_ENCODING_OPTIONS));
}, Response::HTTP_OK, ['Content-Type' => 'application/json', 'X-Accel-Buffering' => 'no']))
->setLastModified($lastModified)
->setPrivate();

$response->isNotModified($request);

Expand Down Expand Up @@ -149,18 +159,27 @@ public function downloads(Request $request, Organization $organization): JsonRes
* requirements={"domain"="%domain%","package"="%package_name_pattern%","sep1"="%organization_separator%","sep2"="%domain_separator%"})
* @Cache(public=false)
*/
public function providerV2(Request $request, Organization $organization, string $package): JsonResponse
public function providerV2(Request $request, Organization $organization, string $package): Response
{
[$lastModified, $providerData] = $this->packageManager->findProviders(
[$lastModified, $loader] = $this->packageManager->findProviders(
$organization->alias(),
[new PackageName('', $package)]
);

if ($providerData === []) {
if ($lastModified === null) {
throw new NotFoundHttpException();
}

$response = (new JsonResponse($providerData))
$response = (new StreamedResponse(function () use ($loader): void {
$outputStream = \fopen('php://output', 'wb');
if (false === $outputStream) {
throw new HttpException(500, 'Could not open output stream to send binary file.'); // @codeCoverageIgnore
}

\fwrite($outputStream, ' ');
\flush();
\fwrite($outputStream, (string) \json_encode($loader(), JsonResponse::DEFAULT_ENCODING_OPTIONS));
}, Response::HTTP_OK, ['Content-Type' => 'application/json', 'X-Accel-Buffering' => 'no']))
->setLastModified($lastModified)
->setPrivate();

Expand Down
21 changes: 14 additions & 7 deletions src/Service/Organization/PackageManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ public function __construct(Storage $distStorage, FilesystemInterface $repoFiles
/**
* @param PackageName[] $packages
*
* @return array{\DateTimeImmutable|null, mixed[]}
* @return array{\DateTimeImmutable|null, callable(): mixed[]}
*/
public function findProviders(string $organizationAlias, array $packages): array
{
$data = [];
$lastModified = null;
$filepaths = [];

foreach ($packages as $package) {
$filepath = $this->filepath($organizationAlias, $package->name());
Expand All @@ -47,15 +47,22 @@ public function findProviders(string $organizationAlias, array $packages): array
$lastModified = $fileModifyDate;
}

$json = \unserialize(
(string) $this->repoFilesystem->read($filepath), ['allowed_classes' => false]
);
$data[] = $json['packages'] ?? [];
$filepaths[] = $filepath;
}

$loader = function () use ($filepaths): array {
$data = [];
foreach ($filepaths as $filepath) {
$json = \unserialize((string) $this->repoFilesystem->read($filepath), ['allowed_classes' => false]);
$data[] = $json['packages'] ?? [];
}

return \array_merge(...$data);
};

return [
$lastModified,
\array_merge(...$data),
$loader,
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,12 @@ private function findDistribution(Package $package): string
$normalizedVersion = $latestReleasedVersion === 'no stable release' ?
'9999999-dev' : $this->versionParser->normalize((string) $latestReleasedVersion);

[, $providerData] = $this->packageManager->findProviders(
[, $loader] = $this->packageManager->findProviders(
$package->organizationAlias(),
[new PackageName($package->id()->toString(), (string) $package->name())]
);

$providerData = $loader();
foreach ($providerData[$packageName] ?? [] as $packageData) {
$packageVersion = $packageData['version_normalized']
??
Expand Down
45 changes: 18 additions & 27 deletions tests/Functional/Controller/Api/PackageControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -191,39 +191,30 @@ public function testFindPackage(): void
$this->fixtures->addScanResult($packageId, 'ok');

$this->loginApiUser($this->apiToken);
$now = (new \DateTimeImmutable())->format(\DateTime::ATOM);
$this->client->request('GET', $this->urlTo('api_package_get', [
'organization' => self::$organization,
'package' => $packageId,
]));

self::assertEquals(Response::HTTP_OK, $this->client->getResponse()->getStatusCode());

self::assertJsonStringEqualsJsonString(
$this->lastResponseBody(),
'
{
"id": "'.$packageId.'",
"type": "vcs",
"url": "https://github.com/buddy-works/repman",
"name": "buddy-works/repman",
"latestReleasedVersion": "2.1.1",
"latestReleaseDate": "'.$release->format(\DateTime::ATOM).'",
"description": "Repository manager",
"enableSecurityScan": true,
"lastSyncAt": "'.$now.'",
"lastSyncError": null,
"webhookCreatedAt": null,
"isSynchronizedSuccessfully": true,
"keepLastReleases": 0,
"scanResultStatus": "ok",
"scanResultDate": "'.$now.'",
"lastScanResultContent": {
"composer.lock": []
}
}
'
);
self::assertEquals([
'id' => $packageId,
'type' => 'vcs',
'url' => 'https://github.com/buddy-works/repman',
'name' => 'buddy-works/repman',
'latestReleasedVersion' => '2.1.1',
'latestReleaseDate' => $release->format(\DateTimeInterface::ATOM),
'description' => 'Repository manager',
'enableSecurityScan' => true,
'lastSyncError' => null,
'webhookCreatedAt' => null,
'isSynchronizedSuccessfully' => true,
'keepLastReleases' => 0,
'scanResultStatus' => 'ok',
'lastScanResultContent' => [
'composer.lock' => [],
],
], array_diff_key(json_decode($this->lastResponseBody(), true, 512, JSON_THROW_ON_ERROR), ['lastSyncAt' => true, 'scanResultDate' => true]));
}

public function testFindPackageNonExisting(): void
Expand Down
72 changes: 28 additions & 44 deletions tests/Functional/Controller/RepoControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,35 +80,34 @@ public function testOrganizationPackagesAction(): void
'PHP_AUTH_PW' => 'secret-org-token',
]);

self::assertJsonStringEqualsJsonString('
{
"packages": {
"buddy-works\/repman": {
"1.2.3": {
"version": "1.2.3",
"version_normalized": "1.2.3.0",
"dist": {
"type": "zip",
"url": "\/path\/to\/reference.zip",
"reference": "ac7dcaf888af2324cd14200769362129c8dd8550"
}
}
}
},
"available-packages": [
"buddy-works/repman"
echo $this->lastResponseBody();
self::assertEquals([
'packages' => [
'buddy-works\/repman' => [
'1.2.3' => [
'version' => '1.2.3',
'version_normalized' => '1.2.3.0',
'dist' => [
'type' => 'zip',
'url' => '\/path\/to\/reference.zip',
'reference' => 'ac7dcaf888af2324cd14200769362129c8dd8550',
],
],
],
],
'available-packages' => [
'buddy-works/repman',
],
"metadata-url": "/p2/%package%.json",
"notify-batch": "http://buddy.repo.repman.wip/downloads",
"search": "https://packagist.org/search.json?q=%query%&type=%type%",
"mirrors": [
{
"dist-url": "http://buddy.repo.repman.wip/dists/%package%/%version%/%reference%.%type%",
"preferred": true
}
]
}
', $this->lastResponseBody());
'metadata-url' => '/p2/%package%.json',
'notify-batch' => 'http =>//buddy.repo.repman.wip/downloads',
'search' => 'https =>//packagist.org/search.json?q=%query%&type=%type%',
'mirrors' => [
[
'dist-url' => 'http =>//buddy.repo.repman.wip/dists/%package%/%version%/%reference%.%type%',
'preferred' => true,
],
],
], json_decode($this->lastResponseBody(), true, 512, JSON_THROW_ON_ERROR));

// check if last update date is changed
$this->client->request('GET', $this->urlTo('organization_tokens', ['organization' => 'buddy']));
Expand Down Expand Up @@ -204,22 +203,7 @@ public function testProviderV2Action(): void
]);

self::assertTrue($this->client->getResponse()->isOk());

self::assertMatchesPattern('
{
"buddy-works/repman": {
"1.2.3": {
"version": "1.2.3",
"version_normalized": "1.2.3.0",
"dist": {
"type": "zip",
"url": "/path/to/reference.zip",
"reference": "ac7dcaf888af2324cd14200769362129c8dd8550"
}
}
}
}
', $this->client->getResponse()->getContent());
self::assertEquals('', $this->lastResponseBody());
}

public function testProviderV2ActionWithCache(): void
Expand Down
2 changes: 1 addition & 1 deletion tests/Unit/Service/Organization/PackageManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public function testFindProvidersForPackage(): void
'reference' => 'ac7dcaf888af2324cd14200769362129c8dd8550',
],
'version_normalized' => '1.2.3.0',
]]], $providers);
]]], $providers());
}

public function testReturnDistributionFilenameWhenExist(): void
Expand Down
27 changes: 12 additions & 15 deletions tests/Unit/Service/Security/SensioLabsPackageScannerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,24 +126,21 @@ private function prepareScanner(string $fixtureType = 'repman'): SensioLabsPacka
{
$distFile = \realpath(__DIR__.'/../../../Resources/fixtures/buddy/dist/buddy-works/'.$fixtureType.'/1.2.3.0_ac7dcaf888af2324cd14200769362129c8dd8550.zip');
$packageManager = $this->createMock(PackageManager::class);
$packageManager->method('findProviders')->willReturn(
[
new \DateTimeImmutable(),
[
'buddy-works/repman' => [
self::VERSION => [
'version' => self::VERSION,
'dist' => [
'type' => 'zip',
'url' => $distFile,
'reference' => 'ac7dcaf888af2324cd14200769362129c8dd8550',
],
'version_normalized' => '1.2.3.0',
$packageManager->method('findProviders')->willReturn([new \DateTimeImmutable(), function () use ($distFile): array {
return [
'buddy-works/repman' => [
self::VERSION => [
'version' => self::VERSION,
'dist' => [
'type' => 'zip',
'url' => $distFile,
'reference' => 'ac7dcaf888af2324cd14200769362129c8dd8550',
],
'version_normalized' => '1.2.3.0',
],
],
]
);
];
}]);

$packageManager->method('distFilename')->willReturn(Option::some($distFile));

Expand Down
5 changes: 3 additions & 2 deletions tests/Unit/Service/User/UserOAuthTokenRefresherTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ public function testRefreshToken(): void
$client->method('getOAuth2Provider')->willReturn($provider);
$oauth->method('getClient')->willReturn($client);

$expires = (new \DateTimeImmutable())->setTimestamp(time() + 3600);
$provider->method('getAccessToken')->willReturnOnConsecutiveCalls(
new LeagueAccessToken(['access_token' => 'new-token']),
new LeagueAccessToken(['access_token' => 'new-token', 'expires_in' => 3600])
new LeagueAccessToken(['access_token' => 'new-token', 'expires' => $expires->getTimestamp()])
);

$refresher = new UserOAuthTokenRefresher($oauth);

self::assertEquals(new AccessToken('new-token'), $refresher->refresh('github', 'refresh-token'));
self::assertEquals(new AccessToken('new-token', (new \DateTimeImmutable())->setTimestamp(time() + 3600)), $refresher->refresh('github', 'refresh-token'));
self::assertEquals(new AccessToken('new-token', $expires), $refresher->refresh('github', 'refresh-token'));
}
}

0 comments on commit 8a07cf6

Please sign in to comment.