Update logging and a few other small cleanup areas (#110)

This commit is contained in:
Tyler Wilding 2022-07-22 22:35:39 -04:00 committed by GitHub
parent a26d4531b7
commit 00f6218015
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 420 additions and 249 deletions

View file

@ -45,6 +45,7 @@ jobs:
ls ./src-tauri/data/
- uses: tauri-apps/tauri-action@v0
timeout-minutes: 30
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}

View file

@ -94,6 +94,7 @@ jobs:
ls ./src-tauri/data
- uses: tauri-apps/tauri-action@v0
timeout-minutes: 30
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}

View file

@ -11,7 +11,7 @@
import { isInDebugMode } from "$lib/setup/setup";
import { appWindow } from "@tauri-apps/api/window";
import { isInstalling } from "./lib/stores/AppStore";
import { loadTranslations } from "$lib/translations/translations";
import { log } from "$lib/utils/log";
let revokeSpecificActions = false;
@ -58,7 +58,7 @@ import { loadTranslations } from "$lib/translations/translations";
// Shift+Ctrl F12
if (e.code == "F12" && e.ctrlKey && e.shiftKey) {
revokeSpecificActions = false;
console.log("hello world");
log.info("Hello World - Dev Tools Enabled!");
}
});
}

View file

@ -1,25 +1,41 @@
<script>
<script lang="ts">
import logoJak1 from "$assets/images/jak-tpl.webp";
import logoJak2 from "$assets/images/jak-2.webp";
import logoJak3 from "$assets/images/jak-3.webp";
import { Link } from "svelte-navigator";
import { link } from "svelte-navigator";
import { useLocation } from "svelte-navigator";
let location = useLocation();
</script>
<nav id="sidebar">
<div class="games">
<div class="jak-1 nav-item active">
<Link to="/jak1" data-tooltip="Jak & Daxter: The Precursor Legacy">
<div
class="jak-1 nav-item"
class:active={["/", "/jak1"].includes($location.pathname)}
>
<a
href="/jak1"
use:link
data-tooltip="Jak & Daxter: The Precursor Legacy"
>
<img src={logoJak1} alt="Jak - TPL" />
</Link>
</a>
</div>
<div class="jak-2 nav-item disabled">
<div
class="jak-2 nav-item disabled"
class:active={["/jak2"].includes($location.pathname)}
>
<!-- <Link to="no" data-tooltip="Jak 2"> -->
<img src={logoJak2} alt="Jak 2" />
<img src={logoJak2} alt="Jak 2" />
<!-- </Link> -->
</div>
<div class="jak-3 nav-item disabled">
<div
class="jak-3 nav-item disabled"
class:active={["/jak3"].includes($location.pathname)}
>
<!-- <Link to="no" data-tooltip="Jak 3"> -->
<img src={logoJak3} alt="Jak 3" />
<img src={logoJak3} alt="Jak 3" />
<!-- </Link> -->
</div>
</div>
@ -30,86 +46,101 @@
<i class="bi bi-terminal-fill" />
</Link>
</div> -->
<div class="settings nav-item">
<Link to="settings" data-tooltip="Settings">
<i class="fa-solid fa-gear"></i>
</Link>
<div
class="settings nav-item"
class:active={["/settings"].includes($location.pathname)}
>
<a href="/settings" use:link data-tooltip="Settings">
<i class="fa-solid fa-gear" />
</a>
</div>
</div>
</nav>
<style>
#sidebar {
display: flex;
flex-direction: column;
height: 100vh;
background-color: var(--bg-blue);
opacity: 75%;
transition: 500ms ease;
width: 10vw;
max-width: 10vw;
}
display: flex;
flex-direction: column;
height: 100vh;
background-color: var(--bg-blue);
opacity: 75%;
transition: 500ms ease;
width: 10vw;
max-width: 10vw;
}
#sidebar:hover {
opacity: 100%;
}
#sidebar:hover {
opacity: 100%;
}
.games {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
height: 50vh;
}
.games {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
height: 50vh;
}
.nav-item {
margin: 0 5px;
filter: grayscale(100%);
transition: 500ms ease;
opacity: 50%;
}
.nav-item {
margin: 0 5px;
filter: grayscale(100%);
transition: 500ms ease;
opacity: 50%;
}
.nav-item.active {
filter: grayscale(0%);
}
.nav-item.active {
filter: grayscale(0%);
}
.nav-item:hover {
filter: grayscale(0%);
opacity: 100%;
cursor: pointer;
}
.nav-item:hover {
filter: grayscale(0%);
opacity: 100%;
cursor: pointer;
}
.nav-item.disabled:hover,
.nav-item.disabled {
cursor: not-allowed;
filter: grayscale(100%);
}
.nav-item.disabled:hover,
.nav-item.disabled {
cursor: not-allowed;
filter: grayscale(100%);
}
.nav-item a::before,
.nav-item a::after {
--scale: 0;
position: absolute;
transform: translateX(55px) scale(var(--scale));
transition: 200ms ease;
transform-origin: left center;
}
.nav-item a::before,
.nav-item a::after {
--scale: 0;
position: absolute;
transform: translateX(55px) scale(var(--scale));
transition: 200ms ease;
transform-origin: left center;
}
.nav-item a::before {
padding: 0.5rem;
width: max-content;
background: #333;
color: white;
content: attr(data-tooltip);
border-radius: 0.3rem;
text-align: center;
}
.nav-item a::before {
padding: 0.5rem;
width: max-content;
background: #333;
color: white;
content: attr(data-tooltip);
border-radius: 0.3rem;
text-align: center;
}
.nav-item a:hover::before {
--scale: 1;
}
.nav-item a:hover::before {
--scale: 1;
}
.nav-item img {
width: 100%;
}
.nav-item img {
width: 100%;
}
.controls {
margin-bottom: 2em;
justify-content: flex-end;
}
.settings.active i {
color: #f18c31;
}
.settings:hover i {
color: #f18c31;
}
</style>

View file

@ -3,6 +3,7 @@ import { appDir, join } from "@tauri-apps/api/path";
import { Store } from "tauri-plugin-store-api";
import { SupportedGame } from "./constants";
import { fileExists } from "./utils/file";
import { log } from "./utils/log";
class GameConfig {
isInstalled: boolean = false;
@ -54,13 +55,13 @@ export async function initConfig() {
const path = await join(await appDir(), "settings.json");
let configExists = await fileExists(path);
if (!configExists) {
console.log("[Launcher]: Settings file not found or could not be loaded!");
log.info("settings file not found or could not be loaded!");
await createDir(await appDir(), { recursive: true });
await writeFile({
contents: JSON.stringify(new LauncherConfig(), null, 2),
path: path,
});
console.log("[Launcher]: Settings file initialized");
log.info("settings file initialized");
}
}
@ -146,7 +147,7 @@ export async function isAVXRequirementMet(): Promise<boolean> {
await store.load();
let requirements = await store.get("requirements");
if (!requirements["avx"]) {
console.log("Unsupported AVX");
log.error("requirement false - AVX unsupported");
return false;
}
return true;
@ -156,7 +157,7 @@ export async function isOpenGLRequirementMet(): Promise<boolean> {
await store.load();
let requirements = await store.get("requirements");
if (!requirements["openGL"]) {
console.log("Unsupported OpenGL");
log.error("requirement false - OpenGL unsupported");
return false;
}
return true;
@ -203,8 +204,9 @@ export async function shouldUpdateGameInstall(
return false;
}
console.log("Tools version is different than install verison");
console.log("Tools: ", toolsVersion);
console.log("Installed: ", installVersion);
log.warn("Tools version is different than install verison", {
tools: toolsVersion,
installed: installVersion,
});
return true;
}

View file

@ -1,3 +1,4 @@
import { log } from "$lib/utils/log";
import { invoke } from "@tauri-apps/api/tauri";
export async function getHighestSimd(): Promise<string> {
@ -16,7 +17,7 @@ export async function openDir(dir: string): Promise<void> {
try {
return await invoke("open_dir", { dir });
} catch (e) {
console.log(e);
log.error(e);
}
}
@ -24,7 +25,7 @@ export async function closeSplashScreen() {
try {
invoke("close_splashscreen");
} catch (e) {
console.log(e);
log.error(e);
}
}
@ -32,6 +33,6 @@ export async function copyDirectory(source: string, destination: string) {
try {
return await invoke("copy_dir", { dirSrc: source, dirDest: destination });
} catch (e) {
console.log(e);
log.error(e);
}
}

View file

@ -3,20 +3,15 @@ import { appDir, join } from "@tauri-apps/api/path";
import { os } from "@tauri-apps/api";
import { getHighestSimd } from "$lib/rpc/commands";
import { InstallStatus, isInstalling } from "../stores/AppStore";
import { SETUP_SUCCESS, SupportedGame } from "$lib/constants";
import {
appendToInstallErrorLog,
appendToInstallLog,
clearInstallLogs,
filePrompt,
} from "$lib/utils/file";
import { SETUP_ERROR, SETUP_SUCCESS, SupportedGame } from "$lib/constants";
import { filePrompt } from "$lib/utils/file";
import {
setGameInstallVersion,
setInstallStatus,
setRequirementsMet,
} from "../config";
import { BaseDirectory, copyFile } from "@tauri-apps/api/fs";
import { resolveErrorCode } from "./setup_errors";
import { installLog, log } from "$lib/utils/log";
let sidecarOptions = {};
@ -51,6 +46,11 @@ export async function isOpenGLVersionSupported(
if (output.code === 0) {
return true;
}
log.error("opengl requirement check failed", {
statusCode: output.code,
stdout: output.stdout,
stderr: output.stderr,
});
throw new Error("UNSUPPORTED OPENGL VERSION");
}
@ -65,12 +65,6 @@ export async function checkRequirements(): Promise<Boolean> {
}
}
export async function saveISO(filePath: string): Promise<any> {
const appDirPath = await appDir();
await copyFile(filePath, `${appDirPath}/jak.iso`, { dir: BaseDirectory.App });
return;
}
async function handleErrorCode(code: number, stepName: string) {
isInstalling.update(() => false);
const explaination = await resolveErrorCode(code);
@ -80,6 +74,17 @@ async function handleErrorCode(code: number, stepName: string) {
throw new Error(explaination);
}
async function isoPrompt(): Promise<string> {
InstallStatus.update(() => SETUP_SUCCESS.awaitingISO);
const path = await filePrompt(["ISO", "iso"], "Jak ISO File");
if (path === null) {
InstallStatus.update(() => SETUP_ERROR.noISO);
throw new Error("No ISO File Selected!");
}
return path;
}
/**
* @param {String} filePath
* @returns {Promise<Boolean>}
@ -101,10 +106,14 @@ export async function extractAndValidateISO(
const output = await command.execute();
if (output.stdout) {
await appendToInstallLog(SupportedGame.Jak1, output.stdout);
installLog.info(output.stdout, {
game: SupportedGame.Jak1,
});
}
if (output.stderr) {
await appendToInstallErrorLog(SupportedGame.Jak1, output.stdout);
installLog.error(output.stderr, {
game: SupportedGame.Jak1,
});
}
if (output.code === 0) {
return true;
@ -131,10 +140,14 @@ export async function decompileGameData(filePath: string): Promise<boolean> {
const output = await command.execute();
if (output.stdout) {
await appendToInstallLog(SupportedGame.Jak1, output.stdout);
installLog.info(output.stdout, {
game: SupportedGame.Jak1,
});
}
if (output.stderr) {
await appendToInstallErrorLog(SupportedGame.Jak1, output.stdout);
installLog.error(output.stderr, {
game: SupportedGame.Jak1,
});
}
if (output.code === 0) {
return true;
@ -159,10 +172,14 @@ export async function compileGame(filePath: string): Promise<Boolean> {
const output = await command.execute();
if (output.stdout) {
await appendToInstallLog(SupportedGame.Jak1, output.stdout);
installLog.info(output.stdout, {
game: SupportedGame.Jak1,
});
}
if (output.stderr) {
await appendToInstallErrorLog(SupportedGame.Jak1, output.stdout);
installLog.error(output.stderr, {
game: SupportedGame.Jak1,
});
}
if (output.code === 0) {
InstallStatus.update(() => SETUP_SUCCESS.ready);
@ -175,8 +192,7 @@ export async function fullInstallation(game: SupportedGame): Promise<boolean> {
let isoPath: string | string[];
isInstalling.update(() => true);
try {
await clearInstallLogs(game);
isoPath = await filePrompt();
isoPath = await isoPrompt();
await extractAndValidateISO(isoPath);
await decompileGameData(isoPath);
await compileGame(isoPath);
@ -185,7 +201,9 @@ export async function fullInstallation(game: SupportedGame): Promise<boolean> {
await setGameInstallVersion(game);
return true;
} catch (err) {
console.log(`[OG]: Error encountered - ${err}`);
installLog.error("unexpected error encountered", {
error: err,
});
let errStatus = {
status: err,
percent: undefined,
@ -204,7 +222,6 @@ export async function recompileGame(game: SupportedGame) {
// TODO - probably should check the dir exists
isInstalling.update(() => true);
try {
await clearInstallLogs(game);
// decompile & compile game
await decompileGameData(isoPath);
await compileGame(isoPath);
@ -212,7 +229,9 @@ export async function recompileGame(game: SupportedGame) {
await setGameInstallVersion(game);
isInstalling.update(() => false);
} catch (err) {
console.log(`[OG]: Error encountered - ${err}`);
installLog.error("unexpected error encountered", {
error: err,
});
let errStatus = {
status: err,
percent: undefined,

View file

@ -1,6 +1,7 @@
import { fileExists } from "../utils/file";
import { appDir, join } from "@tauri-apps/api/path";
import { readTextFile } from "@tauri-apps/api/fs";
import { log } from "$lib/utils/log";
interface ErrorCodeMetadataEntry {
msg: string;
@ -20,9 +21,9 @@ export async function resolveErrorCode(
"error-code-metadata.json"
);
if (!(await fileExists(errorMetadataPath))) {
console.log(
`[OG]: Could not locate error metadata file at ${errorMetadataPath}`
);
log.warn("could not locate error metadata file at path", {
path: errorMetadataPath,
});
return undefined;
}
const jsonData = JSON.parse(await readTextFile(errorMetadataPath));

View file

@ -1,6 +1,7 @@
import { Convert } from "./translation_schema";
import type { TranslationSchema } from "./translation_schema";
import english from "$assets/translations/english.json";
import { log } from "$lib/utils/log";
let supportedTranslations = ["english"];
@ -8,10 +9,12 @@ export let TranslatedStrings: TranslationSchema;
export function loadTranslations(language: string) {
if (!supportedTranslations.includes(language)) {
console.log("Language not supported!");
log.error("Language not supported!", {
language: language,
});
}
// TODO - would prefer to import this by a raw path but have to import
// for vite reasons -- maybe there is a different way?
// for vite reasons -- maybe there is a different way to ensure they are bundled?
if (language === "english") {
TranslatedStrings = Convert.toTranslationSchema(JSON.stringify(english));
}

View file

@ -0,0 +1,52 @@
import { copyDirectory } from "$lib/rpc/commands";
import { readTextFile } from "@tauri-apps/api/fs";
import { join, appDir, resourceDir } from "@tauri-apps/api/path";
import { dirExists, fileExists } from "./file";
import { log } from "./log";
export async function dataDirectoryExists(): Promise<boolean> {
return await dirExists(await join(await appDir(), "data"));
}
export async function isDataDirectoryUpToDate(): Promise<boolean> {
const resourceDirPath = await resourceDir();
const appDirPath = await appDir();
// There should be a `metadata.json` which will help us know if the directory is out of date
// aka, does the app have updated files compared to what the user has in their appDir.
const userMetaPath = await join(appDirPath, "data", "metadata.json");
const appMetaPath = await join(resourceDirPath, "data", "metadata.json");
if (!(await fileExists(userMetaPath))) {
log.warn("couldn't locate user's metadata file at path", {
path: userMetaPath,
});
return false;
}
// If it's there, read it in and check the version, compare with the app's
const userMetaVersion = JSON.parse(await readTextFile(userMetaPath)).version;
const appMetaVersion = JSON.parse(await readTextFile(appMetaPath)).version;
if (userMetaVersion != appMetaVersion) {
log.warn("user version does not match app version", {
userVersion: userMetaPath,
appVersion: appMetaVersion,
});
return false;
}
// NOTE - the user can of course mess up their directory more, but we can only hold their hands so much
// TODO - better to add some sort of "verify local data" feature in the app imo
return true;
}
export async function copyDataDirectory(): Promise<boolean> {
const resourceDirPath = await resourceDir();
const appDirPath = await appDir();
let src = `${resourceDirPath.replaceAll("\\\\?\\", "")}data`;
let dst = `${appDirPath}data`;
try {
await copyDirectory(src, dst);
return true;
} catch (e) {
return false;
}
}

View file

@ -1,22 +1,7 @@
import { copyDirectory } from "$lib/rpc/commands";
import { SETUP_SUCCESS, SETUP_ERROR, SupportedGame } from "$lib/constants";
import { invoke } from "@tauri-apps/api";
import { SETUP_SUCCESS, SETUP_ERROR } from "$lib/constants";
import { open } from "@tauri-apps/api/dialog";
import {
createDir,
readDir,
readTextFile,
writeFile,
} from "@tauri-apps/api/fs";
import {
appDir,
dataDir,
dirname,
join,
logDir,
resourceDir,
} from "@tauri-apps/api/path";
import { InstallStatus, ProcessLogs } from "../stores/AppStore";
import { readDir, readTextFile } from "@tauri-apps/api/fs";
import { InstallStatus } from "../stores/AppStore";
export async function fileExists(path: string): Promise<boolean> {
try {
@ -37,123 +22,19 @@ export async function dirExists(path: string): Promise<boolean> {
}
}
export async function filePrompt(): Promise<string> {
// TODO - shouldn't be ISO specific in this function
// TODO - pull strings out into args
InstallStatus.update(() => SETUP_SUCCESS.awaitingISO);
export async function filePrompt(
extensions: string[],
name: string
): Promise<string | null> {
const path = await open({
multiple: false,
directory: false,
filters: [{ extensions: ["ISO", "iso"], name: "Jak ISO File" }],
filters: [{ extensions: extensions, name: name }],
});
if (Array.isArray(path) || path === null) {
InstallStatus.update(() => SETUP_ERROR.noISO);
throw new Error("No ISO File Selected!");
return null;
}
return path;
}
// TODO - move this stuff into a separate file, this isn't generic file util stuff anymore
export async function dataDirectoryExists(): Promise<boolean> {
return await dirExists(await join(await appDir(), "data"));
}
export async function isDataDirectoryUpToDate(): Promise<boolean> {
const resourceDirPath = await resourceDir();
const appDirPath = await appDir();
// There should be a `metadata.json` which will help us know if the directory is out of date
// aka, does the app have updated files compared to what the user has in their appDir.
const userMetaPath = await join(appDirPath, "data", "metadata.json");
const appMetaPath = await join(resourceDirPath, "data", "metadata.json");
if (!(await fileExists(userMetaPath))) {
console.log(
`[Launcher]: Couldn't locate user's metadata file at '${userMetaPath}'`
);
return false;
}
// If it's there, read it in and check the version, compare with the app's
const userMetaVersion = JSON.parse(await readTextFile(userMetaPath)).version;
const appMetaVersion = JSON.parse(await readTextFile(appMetaPath)).version;
if (userMetaVersion != appMetaVersion) {
console.log(
`[Launcher]: User version ${userMetaVersion} does not match app version ${appMetaVersion}`
);
return false;
}
// NOTE - the user can of course mess up their directory more, but we can only hold their hands so much
// TODO - better to add some sort of "verify local data" feature in the app imo
return true;
}
export async function copyDataDirectory(): Promise<boolean> {
const resourceDirPath = await resourceDir();
const appDirPath = await appDir();
let src = `${resourceDirPath.replaceAll("\\\\?\\", "")}data`;
let dst = `${appDirPath}data`;
try {
await copyDirectory(src, dst);
return true;
} catch (e) {
return false;
}
}
// TODO - move this to a logging file and replace all `console.logs` in the entire project
export async function clearInstallLogs(supportedGame: SupportedGame) {
ProcessLogs.set(null);
const dir = await logDir();
let fileName = `${supportedGame}-install.log`;
let fullPath = await join(dir, fileName);
if (await fileExists(fullPath)) {
await writeFile({ contents: "", path: fullPath });
}
fileName = `${supportedGame}-install-errors.log`;
fullPath = await join(dir, fileName);
if (await fileExists(fullPath)) {
await writeFile({ contents: "", path: fullPath });
}
}
export async function appendToInstallLog(
supportedGame: SupportedGame,
text: string
) {
const dir = await logDir();
const fileName = `${supportedGame}-install.log`;
const fullPath = await join(dir, fileName);
console.log(`[OG]: Writing logs to ${fullPath}`);
let contents: string;
if (!(await fileExists(fullPath))) {
await createDir(await dirname(fullPath), { recursive: true });
} else {
contents = await readTextFile(fullPath);
}
contents += text;
ProcessLogs.update(() => contents);
await writeFile({ contents: contents, path: fullPath });
}
export async function appendToInstallErrorLog(
supportedGame: SupportedGame,
text: string
) {
const dir = await logDir();
const fileName = `${supportedGame}-install-errors.log`;
const fullPath = await join(dir, fileName);
console.log(`[OG]: Writing logs to ${fullPath}`);
let contents: string;
if (!(await fileExists(fullPath))) {
await createDir(await dirname(fullPath), { recursive: true });
} else {
contents = await readTextFile(fullPath);
}
contents += text;
ProcessLogs.update(() => contents);
await writeFile({ contents: contents, path: fullPath });
}

173
src/lib/utils/log.ts Normal file
View file

@ -0,0 +1,173 @@
import {
writeFile,
createDir,
readTextFile,
readDir,
} from "@tauri-apps/api/fs";
import { logDir, join, dirname, basename } from "@tauri-apps/api/path";
import { fileExists } from "./file";
enum LogLevel {
Debug = "debug",
Info = "info",
Warn = "warn",
Error = "error",
}
export class Logger {
metadata: Object = {};
level: LogLevel = LogLevel.Debug;
fileNamePrefix: string;
logFileName: string = undefined;
maxFileRotate: number = 10;
buffer: string[] = [];
lastFlush: Date = undefined;
flushMillisecondInterval: number = 2500;
constructor(metadata: Object, level: LogLevel, fileNamePrefix: string) {
this.metadata = metadata;
this.level = level;
this.fileNamePrefix = fileNamePrefix;
}
private logMessage(msg: string, level: LogLevel, meta?: Object): string {
let val = this.metadata;
// Apply provided metadata
if (meta !== undefined) {
for (const [key, value] of Object.entries(meta)) {
val[key] = `${value}`;
}
}
val["level"] = level;
val["message"] = msg;
val["timestamp"] = new Date().toISOString();
return JSON.stringify(val);
}
private async flushToFile(logData: string) {
this.buffer.push(logData);
// Flush if we havn't in X amount of time
if (
this.buffer.length > 0 &&
(this.lastFlush === undefined ||
this.lastFlush.valueOf() >
new Date().valueOf() + this.flushMillisecondInterval)
) {
await this.writeToFile();
this.lastFlush = new Date();
this.buffer = [];
}
}
private async writeToFile() {
// If we havn't figured out our log file name yet, figure it out now
// This is so we don't have to clear our logs manually, just rotate files
if (this.logFileName === undefined) {
this.logFileName = await this.rotateLogFile();
}
// Check if the file exists and read it's contents if so
const dir = await logDir();
const fullPath = await join(dir, this.logFileName);
const logExists = await fileExists(fullPath);
let contents = "";
if (logExists) {
contents = await readTextFile(fullPath);
if (contents === null || contents === undefined) {
contents = "";
}
} else {
await createDir(await dirname(fullPath), { recursive: true });
}
// Build up the string to append and write it
this.buffer.forEach((data) => {
if (data !== undefined && data !== null) {
contents += data + "\n";
}
});
await writeFile({ contents: contents, path: fullPath });
}
private async rotateLogFile(): Promise<string> {
const dir = await logDir();
const logFiles = await readDir(dir);
let numLogs = 0;
let oldestLogIndex = 0;
for (let i = 0; i < logFiles.length; i++) {
const logFile = logFiles[i];
const logFileName = await basename(logFile.path);
// prefix_number.log
const [prefix, number] = logFileName.split("_");
if (prefix === this.fileNamePrefix) {
numLogs++;
oldestLogIndex = Math.min(oldestLogIndex, parseInt(number));
}
}
if (numLogs > this.maxFileRotate) {
return `${this.fileNamePrefix}_${oldestLogIndex}.log`;
} else {
return `${this.fileNamePrefix}_${numLogs}.log`;
}
}
child(meta: Object): Logger {
let newLogger = new Logger(this.metadata, this.level, this.fileNamePrefix);
let newMeta = this.metadata;
for (const [key, value] of Object.entries(meta)) {
newMeta[key] = `${value}`;
}
newLogger.metadata = newMeta;
newLogger.logFileName = this.logFileName;
return newLogger;
}
debug(msg: string, meta?: Object) {
if (this.level <= LogLevel.Debug) {
const logData = this.logMessage(msg, LogLevel.Debug, meta);
console.log(logData);
this.flushToFile(logData);
}
}
info(msg: string, meta?: Object) {
if (this.level <= LogLevel.Info) {
const logData = this.logMessage(msg, LogLevel.Info, meta);
console.log(logData);
this.flushToFile(logData);
}
}
warn(msg: string, meta?: Object) {
if (this.level <= LogLevel.Warn) {
const logData = this.logMessage(msg, LogLevel.Warn, meta);
console.warn(logData);
this.flushToFile(logData);
}
}
error(msg: string, meta?: Object) {
if (this.level <= LogLevel.Error) {
const logData = this.logMessage(msg, LogLevel.Error, meta);
console.error(logData);
this.flushToFile(logData);
}
}
}
export const log = new Logger(
{
name: "launcher",
},
LogLevel.Debug,
"launcher"
);
export const installLog = new Logger(
{
name: "launcher-install",
},
LogLevel.Debug,
"launcher-install"
);

View file

@ -6,8 +6,11 @@
import GameContent from "../components/games/GameControls.svelte";
import GameSetup from "../components/games/setup/GameSetup.svelte";
import { onMount } from "svelte";
import { copyDataDirectory, isDataDirectoryUpToDate } from "$lib/utils/file";
import { gameNeedsReinstall } from "$lib/stores/AppStore";
import {
copyDataDirectory,
isDataDirectoryUpToDate,
} from "$lib/utils/data-files";
const params = useParams();
let activeGame = SupportedGame.Jak1;
@ -85,7 +88,7 @@
{errorText}
{/if}
{:else}
<GameContent {activeGame} on:change={updateGameState}/>
<GameContent {activeGame} on:change={updateGameState} />
{/if}
{:else}
{#if $gameNeedsReinstall}
@ -97,5 +100,5 @@
{/if}
</div>
{:else}
<!-- TODO - component library - spinner -->
<!-- TODO - component library - spinner -->
{/if}

View file

@ -4,7 +4,8 @@
import { checkRequirements } from "$lib/setup/setup";
import { onMount } from "svelte";
import logo from "$assets/images/icon.webp";
import { copyDataDirectory, dataDirectoryExists } from "$lib/utils/file";
import { copyDataDirectory, dataDirectoryExists } from "$lib/utils/data-files";
import { log } from "$lib/utils/log";
let currentProgress = 0;
let currentStatusText = "Initializing Config";
@ -29,7 +30,9 @@
currentProgress = 50;
await copyDataDirectory();
} catch (err) {
console.log(err);
log.error("error encountered when copying data files", {
error: err
});
currentStatusText = `Error - ${err}`;
return;
}