Preserve concurrent article mappings during static sync
This commit is contained in:
parent
25e0f87d97
commit
9d2cd9a895
@ -20,6 +20,7 @@ public function handle(LocalIllustrations $local): int
|
|||||||
return self::FAILURE;
|
return self::FAILURE;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
$baseline = $local->selectionBaseline();
|
||||||
$snapshots = [];
|
$snapshots = [];
|
||||||
$expected = [];
|
$expected = [];
|
||||||
foreach (config('illustrations.categories') as $category => $pool) {
|
foreach (config('illustrations.categories') as $category => $pool) {
|
||||||
@ -33,7 +34,7 @@ public function handle(LocalIllustrations $local): int
|
|||||||
$snapshots[$pool] = $snapshot;
|
$snapshots[$pool] = $snapshot;
|
||||||
$expected[$pool] = $keys;
|
$expected[$pool] = $keys;
|
||||||
}
|
}
|
||||||
$result = $local->synchronize($snapshots);
|
$result = $local->synchronize($snapshots, $baseline);
|
||||||
foreach ($expected as $pool => $keys) {
|
foreach ($expected as $pool => $keys) {
|
||||||
foreach ($keys as $key) {
|
foreach ($keys as $key) {
|
||||||
if (! $local->thumbnail($pool, $key)) $result['pending'][$pool.':'.$key] ??= 'local_copy_unavailable';
|
if (! $local->thumbnail($pool, $key)) $result['pending'][$pool.':'.$key] ??= 'local_copy_unavailable';
|
||||||
|
|||||||
@ -128,9 +128,16 @@ public function storeSelection(string $pool, string $slug, array $image): string
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** One atomic manifest switch after all downloadable files pass verification. */
|
/** One atomic manifest switch after all downloadable files pass verification. */
|
||||||
public function synchronize(array $snapshots): array
|
public function selectionBaseline(): array
|
||||||
{
|
{
|
||||||
return $this->locked(function () use ($snapshots) {
|
$this->manifest = null;
|
||||||
|
return $this->read()['selections'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function synchronize(array $snapshots, ?array $baseline = null): array
|
||||||
|
{
|
||||||
|
$baseline ??= $this->selectionBaseline();
|
||||||
|
return $this->locked(function () use ($snapshots, $baseline) {
|
||||||
$state = $this->read();
|
$state = $this->read();
|
||||||
$pending = [];
|
$pending = [];
|
||||||
foreach ($snapshots as $pool => $snapshot) {
|
foreach ($snapshots as $pool => $snapshot) {
|
||||||
@ -155,6 +162,18 @@ public function synchronize(array $snapshots): array
|
|||||||
$pending[$pool.':'.$slug] = $reason;
|
$pending[$pool.':'.$slug] = $reason;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Receivers may publish new mappings while the remote snapshot is in flight.
|
||||||
|
// Never replace a local change made after this sync's baseline was captured.
|
||||||
|
$current = $state['selections'][$pool] ?? [];
|
||||||
|
$before = $baseline[$pool] ?? [];
|
||||||
|
foreach (array_unique(array_merge(array_keys($before), array_keys($current))) as $slug) {
|
||||||
|
$exists = array_key_exists($slug, $current);
|
||||||
|
if ($exists !== array_key_exists($slug, $before) || ($current[$slug] ?? null) !== ($before[$slug] ?? null)) {
|
||||||
|
if ($exists) $selections[$slug] = $current[$slug];
|
||||||
|
else unset($selections[$slug]);
|
||||||
|
unset($pending[$pool.':'.$slug]);
|
||||||
|
}
|
||||||
|
}
|
||||||
$state['selections'][$pool] = $selections;
|
$state['selections'][$pool] = $selections;
|
||||||
}
|
}
|
||||||
$this->save($state);
|
$this->save($state);
|
||||||
|
|||||||
@ -125,4 +125,18 @@ public function test_missing_manifest_never_fetches_resource_or_returns_remote_f
|
|||||||
$this->assertSame('/tutorial.png', IllustrationPool::thumbnail(['iCategoryId' => 3, 'sSlug' => 'guide'], '/tutorial.png'));
|
$this->assertSame('/tutorial.png', IllustrationPool::thumbnail(['iCategoryId' => 3, 'sSlug' => 'guide'], '/tutorial.png'));
|
||||||
Http::assertNothingSent();
|
Http::assertNothingSent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_sync_does_not_overwrite_concurrent_article_assignments(): void
|
||||||
|
{
|
||||||
|
$this->fakeImages();$local = app(LocalIllustrations::class);$old = $this->image();
|
||||||
|
$local->storeSelection('freenode', 'fn1', $old);
|
||||||
|
$baseline = $local->selectionBaseline();
|
||||||
|
$new = $this->image('33333333-3333-4333-8333-333333333333');
|
||||||
|
$local->storeSelection('freenode', 'fn1', $new);
|
||||||
|
$local->storeSelection('freenode', 'fn2', $new);
|
||||||
|
$local->synchronize(['freenode' => ['items' => [$old], 'selections' => ['fn1' => $old], 'unavailable' => []]], $baseline);
|
||||||
|
$state = json_decode(file_get_contents($this->dir.'/private/manifest.json'), true);
|
||||||
|
$this->assertSame($new['asset_id'], $state['selections']['freenode']['fn1']);
|
||||||
|
$this->assertSame($new['asset_id'], $state['selections']['freenode']['fn2']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user