@@ -38,6 +38,7 @@ import 'package:pub_dev/task/global_lock.dart';
3838import 'package:pub_dev/task/handlers.dart' ;
3939import 'package:pub_dev/task/models.dart'
4040 show
41+ AbortedTokenInfo,
4142 PackageState,
4243 PackageStateInfo,
4344 PackageVersionStateInfo,
@@ -436,9 +437,19 @@ class TaskBackend {
436437
437438 // List of versions that are tracked, but don't exist. These have
438439 // probably been deselected by _versionsToTrack.
439- final deselectedVersions = [
440- ...state.versions! .keys.whereNot (versions.contains),
441- ];
440+ final deselectedVersions = < String > [];
441+ for (final e in state.versions! .entries) {
442+ if (! versions.contains (e.key)) {
443+ deselectedVersions.add (e.key);
444+
445+ final token = e.value.secretToken;
446+ if (token != null ) {
447+ state.abortedTokens ?? = < AbortedTokenInfo > [];
448+ state.abortedTokens! .add (AbortedTokenInfo (
449+ token: token, expires: clock.fromNow (days: 1 )));
450+ }
451+ }
452+ }
442453
443454 // There should never be an overlap between versions untracked and
444455 // versions that tracked by now deselected.
@@ -467,6 +478,7 @@ class TaskBackend {
467478 ),
468479 });
469480 state.derivePendingAt ();
481+ state.abortedTokens? .removeWhere ((t) => t.expires.isAfter (clock.now ()));
470482
471483 _log.info ('Update state tracking for $packageName ' );
472484 tx.insert (state);
@@ -611,18 +623,8 @@ class TaskBackend {
611623
612624 final key = PackageState .createKey (_db, runtimeVersion, package);
613625 final state = await _db.lookupOrNull <PackageState >(key);
614- if (state == null || state.versions! [version] == null ) {
615- throw NotFoundException .resource ('$package /$version ' );
616- }
617- final versionState = state.versions! [version]! ;
618-
619- // Check the secret token
620- if (! versionState.isAuthorized (_extractBearerToken (request))) {
621- throw AuthenticationException .authenticationRequired ();
622- }
623- assert (versionState.scheduled != initialTimestamp);
624- assert (versionState.instance != null );
625- assert (versionState.zone != null );
626+ final versionState =
627+ _extractAndVerifyVersionState (package, version, state, request);
626628
627629 // Set expiration of signed URLs to remaining execution time + 5 min to
628630 // allow for clock skew.
@@ -685,24 +687,13 @@ class TaskBackend {
685687 await withRetryTransaction (_db, (tx) async {
686688 final key = PackageState .createKey (_db, runtimeVersion, package);
687689 final state = await tx.lookupOrNull <PackageState >(key);
688- if (state == null || state.versions! [version] == null ) {
689- throw TaskAbortedException (
690- '$package /$version is no longer selected for analysis.' );
691- }
692- final versionState = state.versions! [version]! ;
693-
694- // Check the secret token
695- if (! versionState.isAuthorized (_extractBearerToken (request))) {
696- throw TaskAbortedException ('Secret token is no longer accepted.' );
697- }
698- assert (versionState.scheduled != initialTimestamp);
699- assert (versionState.instance != null );
700- assert (versionState.zone != null );
690+ final versionState =
691+ _extractAndVerifyVersionState (package, version, state, request);
701692
702693 // Update dependencies, if pana summary has dependencies
703694 if (summary != null && summary.allDependencies != null ) {
704695 final updatedDependencies = _updatedDependencies (
705- state.dependencies,
696+ state! .dependencies,
706697 summary.allDependencies,
707698 // for logging only
708699 package: package,
@@ -720,7 +711,7 @@ class TaskBackend {
720711 instance = versionState.instance! ;
721712
722713 // Remove instanceName, zone, secretToken, and set attempts = 0
723- state.versions! [version] = PackageVersionStateInfo (
714+ state! .versions! [version] = PackageVersionStateInfo (
724715 scheduled: versionState.scheduled,
725716 docs: hasDocIndexHtml,
726717 pana: summary != null ,
@@ -1170,6 +1161,41 @@ String? _extractBearerToken(shelf.Request request) {
11701161 return parts.last.trim ();
11711162}
11721163
1164+ PackageVersionStateInfo _extractAndVerifyVersionState (
1165+ String package,
1166+ String version,
1167+ PackageState ? state,
1168+ shelf.Request request,
1169+ ) {
1170+ final token = _extractBearerToken (request);
1171+ if (token == null ) {
1172+ throw AuthenticationException .authenticationRequired ();
1173+ }
1174+ if (state == null ) {
1175+ throw NotFoundException .resource ('$package /$version ' );
1176+ }
1177+ final versionState = state.versions! [version];
1178+ if (versionState == null ) {
1179+ // check if the task was aborted
1180+ final abortedToken =
1181+ state.abortedTokens? .firstWhereOrNull ((t) => t.token == token);
1182+ if (abortedToken != null && abortedToken.expires.isBefore (clock.now ())) {
1183+ throw TaskAbortedException ('$package /$version has been aborted.' );
1184+ }
1185+ // otherwise throw a generic not found error
1186+ throw NotFoundException .resource ('$package /$version ' );
1187+ }
1188+
1189+ // Check the secret token
1190+ if (! versionState.isAuthorized (token)) {
1191+ throw AuthenticationException .authenticationRequired ();
1192+ }
1193+ assert (versionState.scheduled != initialTimestamp);
1194+ assert (versionState.instance != null );
1195+ assert (versionState.zone != null );
1196+ return versionState;
1197+ }
1198+
11731199/// Given a list of versions return the list of versions that should be
11741200/// tracked for analysis.
11751201///
0 commit comments