All files / src/web startup.js

100% Statements 31/31
100% Branches 29/29
100% Functions 4/4
100% Lines 27/27

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88                    27x 27x 27x   27x 27x                                                               7x 7x         1x 6x   6x   2x 2x   1x 1x   1x 1x   1x 1x   1x     6x   6x   6x 6x       2x 2x 2x 2x    
import { BuiltInImages } from "./media-loader.js";
import { RunMode } from "./emulation-loop.js";
import { bootModeOf, parseMediaParams, processAutobootParams } from "../url-params.js";
 
/**
 * What the URL asks the page to start with, on `model`.
 * @returns {{media: object, autoboot: string, autoType: string, bootMode: string, mayNeedAnotherModel: boolean,
 *   patch: string|undefined}} `media` is what `Machine.start` loads; the rest is for `startAsTheUrlAsks`
 */
export function startupPlan(parsedQuery, model) {
    const { needsAutoboot, autoType } = processAutobootParams(parsedQuery);
    const { discImage, secondDiscImage, mmcImage } = parseMediaParams(parsedQuery);
    const { loadBasic, embedBasic, tape, patch } = parsedQuery;
    // A BASIC program in the URL is the boot, which basicNeedsRun says whether to run.
    const autoboot = loadBasic ? "" : needsAutoboot;
    return {
        media: {
            // Every built-in disc is a BBC one.
            discImage: discImage || (model.isAtom ? null : BuiltInImages[0].file),
            discImageInUrl: !!discImage,
            secondDiscImage: secondDiscImage || null,
            tape,
            mmcImage,
            loadBasic,
            embedBasic,
            basicNeedsRun: loadBasic !== undefined && needsAutoboot === "run",
        },
        autoboot,
        autoType,
        bootMode: bootModeOf(parsedQuery),
        mayNeedAnotherModel: autoboot === "boot" && !!discImage && !parsedQuery.model,
        patch,
    };
}
 
/**
 * Takes the started machine where the URL asked, unless its boot disc needs another machine first.
 * @param {ReturnType<typeof startupPlan>} plan
 * @param {object} deps
 * @param {Promise<object|null>|null} deps.bootDisc the description of the boot disc, when `plan.mayNeedAnotherModel`
 * @param {(details: {boot_mode: string, renderer: string}) => void} deps.noteStart
 * @returns {Promise<boolean>} false when the page is reloading as the machine its boot disc needs
 */
export async function startAsTheUrlAsks(
    plan,
    { bootDisc, machineSwitch, drive0, renderer, noteStart, autoBoot, dbgr, snapshots, loop },
) {
    const disc = await bootDisc;
    if (
        disc &&
        !machineSwitch.satisfies(disc) &&
        (await machineSwitch.switchFor(disc, drive0, { boot: true, replace: true }))
    )
        return false;
    noteStart({ boot_mode: plan.bootMode, renderer });
 
    switch (plan.autoboot) {
        case "boot":
            autoBoot.boot();
            break;
        case "type":
            autoBoot.type(plan.autoType);
            break;
        case "chain":
            autoBoot.chainTape();
            break;
        case "run":
            autoBoot.runTape();
            break;
        default:
            break;
    }
 
    if (plan.patch) dbgr.setPatch(plan.patch);
 
    await snapshots.restorePendingState();
 
    if (loop.mode !== RunMode.debugging) loop.go();
    return true;
}
 
/** Wraps hosting a session so a machine paused when the host asked runs once the session has started. */
export const hostAndRun = (loop, host) => async (name) => {
    const session = await host(name);
    if (session) loop.go();
    return session;
};