Skip to content

Commit

Permalink
VVPPデフォルトエンジンの進捗表示、オンメモリじゃなくする
Browse files Browse the repository at this point in the history
  • Loading branch information
Hiroshiba committed Dec 30, 2024
1 parent 7cc32cc commit 8ee10b3
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 23 deletions.
42 changes: 34 additions & 8 deletions src/backend/electron/engineAndVvppController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { getEngineInfoManager } from "./manager/engineInfoManager";
import { getEngineProcessManager } from "./manager/engineProcessManager";
import { getRuntimeInfoManager } from "./manager/RuntimeInfoManager";
import { getVvppManager } from "./manager/vvppManager";
import { ProgressCallback } from "./type";
import {
EngineId,
EngineInfo,
Expand Down Expand Up @@ -45,9 +46,9 @@ export class EngineAndVvppController {
/**
* VVPPエンジンをインストールする。
*/
async installVvppEngine(vvppPath: string) {
async installVvppEngine(vvppPath: string, onProgress?: ProgressCallback) {
try {
await this.vvppManager.install(vvppPath);
await this.vvppManager.install(vvppPath, onProgress);
return true;
} catch (e) {
log.error(`Failed to install ${vvppPath},`, e);
Expand Down Expand Up @@ -184,6 +185,7 @@ export class EngineAndVvppController {
async downloadAndInstallVvppEngine(
downloadDir: string,
packageInfo: PackageInfo,
onProgress: ProgressCallback<"download" | "install">,
) {
if (packageInfo.packages.length === 0) {
throw new UnreachableError("No packages to download");
Expand All @@ -193,17 +195,39 @@ export class EngineAndVvppController {
const downloadedPaths: string[] = [];
try {
// ダウンロード
onProgress({ type: "download", progress: 0 });

let totalBytes = 0;
packageInfo.packages.forEach((p) => {
totalBytes += p.size;
});

let downloadedBytes = 0;
await Promise.all(
packageInfo.packages.map(async (p) => {
const { url, name, size } = p;
const { url, name } = p;

log.info(`Download ${name} from ${url}, size: ${size}`);
const res = await fetch(url);
const buffer = await res.arrayBuffer();
log.info(`Download ${name} from ${url}`);
const res = await globalThis.fetch(url);
if (!res.ok || res.body == null)
throw new Error(`Failed to download ${name} from ${url}`);
if (failed) return; // 他のダウンロードが失敗していたら中断

const downloadPath = path.join(downloadDir, name);
await fs.promises.writeFile(downloadPath, Buffer.from(buffer)); // TODO: オンメモリじゃなくする
const fileStream = fs.createWriteStream(downloadPath);

const reader = res.body.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
downloadedBytes += value.length;
fileStream.write(value);
onProgress({
type: "download",
progress: (downloadedBytes / totalBytes) * 100,
});
}

log.info(`Downloaded ${name} to ${downloadPath}`);

downloadedPaths.push(downloadPath);
Expand All @@ -213,7 +237,9 @@ export class EngineAndVvppController {
);

// インストール
await this.installVvppEngine(downloadedPaths[0]);
await this.installVvppEngine(downloadedPaths[0], ({ progress }) => {
onProgress({ type: "install", progress });
});
} catch (e) {
failed = true;
log.error(`Failed to download and install VVPP engine:`, e);
Expand Down
3 changes: 3 additions & 0 deletions src/backend/electron/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,9 @@ app.on("ready", async () => {
await engineAndVvppController.downloadAndInstallVvppEngine(
app.getPath("downloads"),
packageInfo,
({ type, progress }) => {
log.info(`VVPP default engine progress: ${type}: ${progress}%`);
},
);
}

Expand Down
41 changes: 30 additions & 11 deletions src/backend/electron/manager/vvppManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { app, dialog } from "electron";
import MultiStream from "multistream";
import { glob } from "glob";
import AsyncLock from "async-lock";
import { ProgressCallback } from "../type";
import {
EngineId,
EngineInfo,
Expand Down Expand Up @@ -109,7 +110,10 @@ export class VvppManager {

private async extractVvpp(
vvppLikeFilePath: string,
onProgress?: ProgressCallback,
): Promise<{ outputDir: string; manifest: MinimumEngineManifestType }> {
onProgress?.({ progress: 0 });

const nonce = new Date().getTime().toString();
const outputDir = path.join(this.vvppEngineDir, ".tmp", nonce);

Expand Down Expand Up @@ -182,7 +186,13 @@ export class VvppManager {
log.log("Single file, not concatenating");
}

const args = ["x", "-o" + outputDir, archiveFile, "-t" + format];
const args = [
"x",
"-o" + outputDir,
archiveFile,
"-t" + format,
"-bsp1", // 進捗出力
];

let sevenZipPath = import.meta.env.VITE_7Z_BIN_NAME;
if (!sevenZipPath) {
Expand All @@ -194,18 +204,23 @@ export class VvppManager {
sevenZipPath,
);
}
log.log(
"Spawning 7z:",
sevenZipPath,
args.map((a) => JSON.stringify(a)).join(" "),
);
log.log("Spawning 7z:", sevenZipPath, args.join(" "));
await new Promise<void>((resolve, reject) => {
const child = spawn(sevenZipPath, args, {
stdio: ["pipe", "pipe", "pipe"],
});

child.stdout?.on("data", (data: Buffer) => {
log.info(`7z STDOUT: ${data.toString("utf-8")}`);
const output = data.toString("utf-8");
log.info(`7z STDOUT: ${output}`);

// 進捗を取得
const progressMatch = output.match(
/^ *(?<percent>\\d+)% ?(?<fileCount>\\d+)? ?(?<file>.*)$/,
)?.groups?.percent;
if (progressMatch) {
onProgress?.({ progress: parseInt(progressMatch[1]) });
}
});

child.stderr?.on("data", (data: Buffer) => {
Expand Down Expand Up @@ -253,11 +268,15 @@ export class VvppManager {
/**
* 追加
*/
async install(vvppPath: string) {
await this.lock.acquire(lockKey, () => this._install(vvppPath));
async install(vvppPath: string, onProgress?: ProgressCallback) {
await this.lock.acquire(lockKey, () => this._install(vvppPath, onProgress));
}
private async _install(vvppPath: string) {
const { outputDir, manifest } = await this.extractVvpp(vvppPath);
private async _install(vvppPath: string, onProgress?: ProgressCallback) {
const { outputDir, manifest } = await this.extractVvpp(
vvppPath,
onProgress,
);

const dirName = this.toValidDirName(manifest);
const engineDirectory = path.join(this.vvppEngineDir, dirName);
const oldEngineDirName = (
Expand Down
6 changes: 6 additions & 0 deletions src/backend/electron/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/** 進捗を返すコールバック */
export type ProgressCallback<T extends string | void = void> = [T] extends [
void,
]
? (payload: { progress: number }) => void
: (payload: { type: T; progress: number }) => void;
8 changes: 4 additions & 4 deletions tests/e2e/electron/example.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ test.beforeEach(async () => {
});

[
{
envName: ".env環境",
envPath: ".env",
},
// {
// envName: ".env環境",
// envPath: ".env",
// },
{
envName: "VVPPデフォルトエンジン",
envPath: ".env.test-electron-default-vvpp",
Expand Down

0 comments on commit 8ee10b3

Please sign in to comment.