Skip to content

Commit 7532023

Browse files
Implement FullRescanMessage and its handler; refactor SyncController to dispatch full rescan jobs async.
Force Full Rescan works and scans everything, but it runs twice. First runs scans everything, second is redundant.
1 parent dc197f7 commit 7532023

File tree

10 files changed

+219
-503
lines changed

10 files changed

+219
-503
lines changed

config/packages/messenger.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,4 @@ framework:
3434
'App\Message\BackgroundQueueItem': sync
3535
'App\Message\ScanContentItem': async_concurrent
3636
# verified if async_concurrent is a valid transport
37+
'App\Message\FullRescanMessage': async_priority_low

config/services.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,3 @@ services:
2828

2929
# add more service definitions when explicit configuration is needed
3030
# please note that last definitions always *replace* previous ones
31-

equal-access-server/src/aceChecker.ts

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class PagePool {
1919

2020
async getPage(): Promise<{page: puppeteer.Page, hasScript: boolean}> {
2121
const availablePage = this.pages.find(p => !p.inUse);
22-
22+
2323
if (availablePage) {
2424
availablePage.inUse = true;
2525
return { page: availablePage.page, hasScript: availablePage.hasScript };
@@ -28,7 +28,7 @@ class PagePool {
2828
if (this.pages.length < this.maxSize) {
2929
console.time('new-pooled-page');
3030
const page = await this.browser.newPage();
31-
31+
3232
await page.setRequestInterception(true);
3333
page.on('request', (request) => {
3434
if (['image', 'stylesheet', 'font', 'media'].includes(request.resourceType())) {
@@ -38,7 +38,7 @@ class PagePool {
3838
}
3939
});
4040
console.timeEnd('new-pooled-page');
41-
41+
4242
const pageEntry = { page, inUse: true, hasScript: false };
4343
this.pages.push(pageEntry);
4444
return { page, hasScript: false };
@@ -98,41 +98,32 @@ export async function closePagePool(): Promise<void> {
9898
// - manual
9999
// - pass
100100
export async function aceCheck(html: string, browser: puppeteer.Browser, guidelineIds?: string | string[], reportLevels?: string | string[]): Promise<Report> {
101-
console.time('total-execution');
102-
101+
103102
if (!pagePool) {
104103
pagePool = new PagePool(browser);
105104
}
106-
107-
console.time('get-page-from-pool');
105+
108106
const { page, hasScript } = await pagePool.getPage();
109-
console.timeEnd('get-page-from-pool');
110-
107+
111108
let scriptAdded = false;
112-
109+
113110
try {
114-
console.time('set-content');
115111
await page.setContent(html, { waitUntil: 'domcontentloaded' });
116-
console.timeEnd('set-content');
117-
112+
113+
118114
let scriptAdded = hasScript;
119115
if (!hasScript) {
120-
console.time('add-script-tag');
116+
121117
await page.addScriptTag({
122118
path: require.resolve(acePath)
123119
});
124120
scriptAdded = true;
125-
console.timeEnd('add-script-tag');
126121
}
127-
128-
console.time('evaluate-check');
122+
129123
const report = await page.evaluate(async (ids) => {
130124
const checker = new ace.Checker();
131125
return await checker.check(document, ids);
132126
}, guidelineIds);
133-
console.timeEnd('evaluate-check');
134-
135-
console.timeEnd('total-execution');
136127

137128
// validate and process reportLevels
138129
if (!reportLevels) {
@@ -181,22 +172,22 @@ export async function aceCheck(html: string, browser: puppeteer.Browser, guideli
181172

182173
export async function runPerformanceTest(browser: puppeteer.Browser, iterations = 5): Promise<void> {
183174
const sampleHtml = `<!DOCTYPE html><html lang="en"><head><title>Test</title></head><body><h1>Heading</h1><img src="test.jpg" /></body></html>`;
184-
175+
185176
console.log(`Running ${iterations} iterations with page pooling...`);
186-
177+
187178
if (!pagePool) {
188179
await initializePagePool(browser, 3);
189180
}
190-
181+
191182
await aceCheck(sampleHtml, browser, ["WCAG_2_1"]);
192-
183+
193184
const times = [];
194185
for (let i = 0; i < iterations; i++) {
195186
const start = Date.now();
196187
await aceCheck(sampleHtml, browser, ["WCAG_2_1"]);
197188
times.push(Date.now() - start);
198189
}
199-
190+
200191
console.log(`Average execution time: ${times.reduce((a, b) => a + b, 0) / times.length}ms`);
201192
console.log(`Individual times: ${times.join(', ')}ms`);
202-
}
193+
}

src/Controller/SyncController.php

Lines changed: 80 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,19 @@
1717
use Symfony\Component\HttpFoundation\Request;
1818
use Symfony\Component\Console\Output\ConsoleOutput;
1919

20+
use App\Message\FullRescanMessage;
21+
use Symfony\Component\Messenger\MessageBusInterface;
22+
2023
class SyncController extends ApiController
2124
{
2225
protected $maxAge = '1D';
26+
private MessageBusInterface $bus;
27+
28+
public function __construct(MessageBusInterface $bus)
29+
{
30+
$this->bus = $bus;
31+
}
32+
2333

2434
/** @var UtilityService $util */
2535
protected $util;
@@ -75,11 +85,67 @@ public function requestSync(Course $course, LmsFetchService $lmsFetch) {
7585
return new JsonResponse($response);
7686
}
7787

88+
// #[Route('/api/sync/rescan/{course}', name: 'full_rescan')]
89+
// public function fullCourseRescan(Course $course, LmsFetchService $lmsFetch){
90+
// $response = new ApiResponse();
91+
// $user = $this->getUser();
92+
// $reportArr = false;
93+
94+
// try {
95+
// if (!$this->userHasCourseAccess($course)) {
96+
// throw new \Exception('msg.no_permissions');
97+
// }
98+
// if ($course->isDirty()) {
99+
// throw new \Exception('msg.course_scanning');
100+
// }
101+
// if (!$course->isActive()) {
102+
// $response->setData(0);
103+
// throw new \Exception('msg.sync.course_inactive');
104+
// }
105+
106+
// $prevReport = $course->getPreviousReport();
107+
108+
// $lmsFetch->refreshLmsContent($course, $user, true);
109+
// // $course->removeAllReports();
110+
111+
// // $lmsFetch->asyncRefreshLmsContent($course, $user);
112+
113+
// $report = $course->getLatestReport();
114+
115+
// if (!$report) {
116+
// throw new \Exception('msg.no_report_created');
117+
// }
118+
119+
// $reportArr = $report->toArray();
120+
// $reportArr['files'] = $course->getFileItems();
121+
// $reportArr['issues'] = $course->getAllIssues();
122+
// $reportArr['contentItems'] = $course->getContentItems();
123+
// $reportArr['contentSections'] = $lmsFetch->getCourseSections($course, $user);
124+
125+
// $response->setData($reportArr);
126+
127+
// if ($prevReport && ($prevReport->getIssueCount() == $report->getIssueCount())) {
128+
// $response->addMessage('msg.no_new_content', 'success', 5000);
129+
// } else {
130+
// $response->addMessage('msg.new_content', 'success', 5000);
131+
// }
132+
// } catch (\Exception $e) {
133+
// if ('msg.course_scanning' === $e->getMessage()) {
134+
// $response->addMessage($e->getMessage(), 'info', 0, false);
135+
// } else {
136+
// $response->addMessage($e->getMessage(), 'error', 0);
137+
// }
138+
// }
139+
140+
// return new JsonResponse($response);
141+
// }
142+
143+
78144
#[Route('/api/sync/rescan/{course}', name: 'full_rescan')]
79-
public function fullCourseRescan(Course $course, LmsFetchService $lmsFetch){
145+
public function fullCourseRescan(Course $course): JsonResponse
146+
{
80147
$response = new ApiResponse();
81148
$user = $this->getUser();
82-
$reportArr = false;
83149

84150
try {
85151
if (!$this->userHasCourseAccess($course)) {
@@ -93,38 +159,19 @@ public function fullCourseRescan(Course $course, LmsFetchService $lmsFetch){
93159
throw new \Exception('msg.sync.course_inactive');
94160
}
95161

96-
$prevReport = $course->getPreviousReport();
97-
98-
$lmsFetch->refreshLmsContent($course, $user, true);
99-
// $course->removeAllReports();
100-
101-
// $lmsFetch->asyncRefreshLmsContent($course, $user);
102-
103-
$report = $course->getLatestReport();
104-
105-
if (!$report) {
106-
throw new \Exception('msg.no_report_created');
107-
}
108-
109-
$reportArr = $report->toArray();
110-
$reportArr['files'] = $course->getFileItems();
111-
$reportArr['issues'] = $course->getAllIssues();
112-
$reportArr['contentItems'] = $course->getContentItems();
113-
$reportArr['contentSections'] = $lmsFetch->getCourseSections($course, $user);
114-
115-
$response->setData($reportArr);
116-
117-
if ($prevReport && ($prevReport->getIssueCount() == $report->getIssueCount())) {
118-
$response->addMessage('msg.no_new_content', 'success', 5000);
119-
} else {
120-
$response->addMessage('msg.new_content', 'success', 5000);
121-
}
162+
// ✅ Use $this->bus
163+
$this->bus->dispatch(new FullRescanMessage(
164+
$course->getId(),
165+
$user->getId(),
166+
$user->getApiKey(),
167+
$user->getInstitution()->getLmsId(),
168+
$user->getInstitution()->getLmsDomain()
169+
));
170+
171+
$response->addMessage('msg.scan_queued', 'success', 5000);
172+
$response->setData(['status' => 'queued']);
122173
} catch (\Exception $e) {
123-
if ('msg.course_scanning' === $e->getMessage()) {
124-
$response->addMessage($e->getMessage(), 'info', 0, false);
125-
} else {
126-
$response->addMessage($e->getMessage(), 'error', 0);
127-
}
174+
$response->addMessage($e->getMessage(), 'error', 0);
128175
}
129176

130177
return new JsonResponse($response);

0 commit comments

Comments
 (0)