run method
Implementation
Future<MissionRunResult> run(
MissionMessage mission, {
MissionCancelToken? cancel,
}) async {
final token = cancel ?? MissionCancelToken();
// Cancelled before it ever ran (a cancel that overtook its mission, or a
// run superseded while queued): exactly ONE frame, `cancelled
// step_index:0` — no `started`, and the exploration log of whatever runs
// next is left alone (Android MissionRunner prologue).
if (token.isCancelled) {
_log('MISSION id=${mission.missionId} cancelled before it ran');
_emitStatus(MissionStatusMessage(
missionId: mission.missionId,
status: MissionStatus.cancelled,
stepIndex: 0,
timestamp: _now(),
error: token.reason ?? 'cancelled',
stepsCompleted: 0,
stepsTotal: mission.declaredStepCount,
stepsSkipped: _range(0, mission.declaredStepCount),
));
return MissionRunResult(
missionId: mission.missionId,
terminalStatus: MissionStatus.cancelled,
stepsCompleted: 0,
error: token.reason ?? 'cancelled',
);
}
// A frame whose steps could not be parsed: answer it honestly instead of
// letting the backend wait out its 25s mission timeout.
if (!mission.isValid) {
final idx = mission.invalidStepIndex ?? 0;
_log('MISSION id=${mission.missionId} invalid (step $idx malformed)');
_emitStatus(MissionStatusMessage(
missionId: mission.missionId,
status: MissionStatus.failed,
stepIndex: idx,
timestamp: _now(),
error: 'invalid_mission',
stepsCompleted: 0,
stepsTotal: mission.declaredStepCount,
// Nothing ran: a malformed frame is refused whole.
stepsSkipped: _range(0, mission.declaredStepCount),
));
return MissionRunResult(
missionId: mission.missionId,
terminalStatus: MissionStatus.failed,
stepsCompleted: 0,
error: 'invalid_mission',
);
}
final start = _now();
var currentStep = 0;
String? firstScreen;
_succeededSteps = 0;
try {
return await _runSteps(mission, token, start, (i) => currentStep = i,
(s) => firstScreen ??= s);
} catch (e, st) {
// Any unexpected throw must STILL surface a terminal status, or the
// backend — and the border glow — hang on `started` forever.
debugPrint('[MissionRunner] mission ${mission.missionId} threw at step '
'$currentStep: $e\n$st');
return _finishMission(mission, currentStep, MissionStatus.failed,
stepIndex: currentStep,
screenAtStart: firstScreen,
missionStart: start,
error: 'exception');
}
}