refactor: replace console.log with tslog

This commit is contained in:
Siyuan Miao 2025-05-23 02:02:00 +02:00
parent c1d771cced
commit fc28ecb19c
30 changed files with 173 additions and 131 deletions

View File

@ -62,6 +62,7 @@ module.exports = defineConfig([{
allowConstantExport: true,
}],
"no-console": ["warn", {}],
"import/order": ["error", {
groups: ["builtin", "external", "internal", "parent", "sibling"],
"newlines-between": "always",

12
ui/package-lock.json generated
View File

@ -36,6 +36,7 @@
"react-xtermjs": "^1.0.10",
"recharts": "^2.15.3",
"tailwind-merge": "^3.3.0",
"tslog": "^4.9.3",
"usehooks-ts": "^3.1.1",
"validator": "^13.15.0",
"zustand": "^4.5.2"
@ -6533,6 +6534,17 @@
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/tslog": {
"version": "4.9.3",
"resolved": "https://registry.npmjs.org/tslog/-/tslog-4.9.3.tgz",
"integrity": "sha512-oDWuGVONxhVEBtschLf2cs/Jy8i7h1T+CpdkTNWQgdAF7DhRo2G8vMCgILKe7ojdEkLhICWgI1LYSSKaJsRgcw==",
"engines": {
"node": ">=16"
},
"funding": {
"url": "https://github.com/fullstack-build/tslog?sponsor=1"
}
},
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",

View File

@ -47,6 +47,7 @@
"react-xtermjs": "^1.0.10",
"recharts": "^2.15.3",
"tailwind-merge": "^3.3.0",
"tslog": "^4.9.3",
"usehooks-ts": "^3.1.1",
"validator": "^13.15.0",
"zustand": "^4.5.2"

View File

@ -19,7 +19,7 @@ import WakeOnLanModal from "@/components/popovers/WakeOnLan/Index";
import MountPopopover from "@/components/popovers/MountPopover";
import ExtensionPopover from "@/components/popovers/ExtensionPopover";
import { useDeviceUiNavigation } from "@/hooks/useAppNavigation";
import { logger } from "@/log";
export default function Actionbar({
requestFullscreen,
}: {
@ -48,7 +48,7 @@ export default function Actionbar({
if (!open) {
setTimeout(() => {
setDisableFocusTrap(false);
console.log("Popover is closing. Returning focus trap to video");
logger.info("Popover is closing. Returning focus trap to video");
}, 0);
}
}

View File

@ -1,7 +1,8 @@
import { useEffect } from "react";
import { useFeatureFlag } from "../hooks/useFeatureFlag";
import { logger } from "@/log";
import { useFeatureFlag } from "../hooks/useFeatureFlag";
export function FeatureFlag({
minAppVersion,
name = "unnamed",
@ -17,7 +18,7 @@ export function FeatureFlag({
useEffect(() => {
if (!appVersion) return;
console.log(
logger.info(
`Feature '${name}' ${isEnabled ? "ENABLED" : "DISABLED"}: ` +
`Current version: ${appVersion}, ` +
`Required min version: ${minAppVersion || "N/A"}`,

View File

@ -9,6 +9,7 @@ import {
useVideoStore,
} from "@/hooks/stores";
import { keys, modifiers } from "@/keyboardMappings";
import { logger } from "@/log";
export default function InfoBar() {
const activeKeys = useHidStore(state => state.activeKeys);
@ -31,9 +32,9 @@ export default function InfoBar() {
useEffect(() => {
if (!rpcDataChannel) return;
rpcDataChannel.onclose = () => console.log("rpcDataChannel has closed");
rpcDataChannel.onclose = () => logger.info("rpcDataChannel has closed");
rpcDataChannel.onerror = e =>
console.log(`Error on DataChannel '${rpcDataChannel.label}': ${e}`);
logger.error(`Error on DataChannel '${rpcDataChannel.label}': ${e}`);
}, [rpcDataChannel]);
const keyboardLedState = useHidStore(state => state.keyboardLedState);

View File

@ -5,6 +5,7 @@ import KeyboardAndMouseConnectedIcon from "@/assets/keyboard-and-mouse-connected
import LoadingSpinner from "@components/LoadingSpinner";
import StatusCard from "@components/StatusCards";
import { HidState } from "@/hooks/stores";
import { logger } from "@/log";
type USBStates = HidState["usbState"];
@ -67,7 +68,7 @@ export default function USBStateStatus({
};
const props = StatusCardProps[state];
if (!props) {
console.log("Unsupported USB state: ", state);
logger.error("Unsupported USB state: ", { state });
return;
}

View File

@ -1,5 +1,7 @@
import { useCallback , useEffect, useState } from "react";
import { logger } from "@/log";
import { useJsonRpc } from "../hooks/useJsonRpc";
import notifications from "../notifications";
import { SettingsItem } from "../routes/devices.$id.settings";
@ -9,6 +11,7 @@ import { Button } from "./Button";
import { SelectMenuBasic } from "./SelectMenuBasic";
import { SettingsSectionHeader } from "./SettingsSectionHeader";
import Fieldset from "./Fieldset";
export interface USBConfig {
vendor_id: string;
product_id: string;
@ -69,7 +72,7 @@ export function UsbDeviceSetting() {
const syncUsbDeviceConfig = useCallback(() => {
send("getUsbDevices", {}, resp => {
if ("error" in resp) {
console.error("Failed to load USB devices:", resp.error);
logger.error("Failed to load USB devices:", resp.error);
notifications.error(
`Failed to load USB devices: ${resp.error.data || "Unknown error"}`,
);

View File

@ -1,7 +1,7 @@
import { useMemo , useCallback , useEffect, useState } from "react";
import { Button } from "@components/Button";
import { jsonRpcLogger, logger } from "@/log";
import { UsbConfigState } from "../hooks/stores";
import { useJsonRpc } from "../hooks/useJsonRpc";
@ -96,12 +96,12 @@ export function UsbInfoSetting() {
const syncUsbConfigProduct = useCallback(() => {
send("getUsbConfig", {}, resp => {
if ("error" in resp) {
console.error("Failed to load USB Config:", resp.error);
jsonRpcLogger.error("Failed to load USB Config:", resp.error);
notifications.error(
`Failed to load USB Config: ${resp.error.data || "Unknown error"}`,
);
} else {
console.log("syncUsbConfigProduct#getUsbConfig result:", resp.result);
jsonRpcLogger.info("syncUsbConfigProduct#getUsbConfig result:", resp.result);
const usbConfigState = resp.result as UsbConfigState;
const product = usbConfigs.map(u => u.value).includes(usbConfigState.product)
? usbConfigState.product
@ -210,7 +210,7 @@ function USBConfigDialog({
const syncUsbConfig = useCallback(() => {
send("getUsbConfig", {}, resp => {
if ("error" in resp) {
console.error("Failed to load USB Config:", resp.error);
logger.error("Failed to load USB Config:", resp.error);
} else {
setUsbConfigState(resp.result as UsbConfigState);
}

View File

@ -18,6 +18,7 @@ import InfoBar from "@components/InfoBar";
import useKeyboard from "@/hooks/useKeyboard";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import notifications from "@/notifications";
import { logger } from "@/log";
import {
HDMIErrorOverlay,
@ -445,7 +446,7 @@ export default function WebRTCVideo() {
// Fix only works in chrome based browsers.
if (e.code === "Space") {
if (videoElm.current?.paused == true) {
console.log("Force playing video");
logger.info("Force playing video");
videoElm.current?.play();
}
}
@ -487,7 +488,7 @@ export default function WebRTCVideo() {
useEffect(
function updateVideoStream() {
if (!mediaStream) return;
console.log("Updating video stream from mediaStream");
logger.info("Updating video stream from mediaStream");
// We set the as early as possible
addStreamToVideoElm(mediaStream);
},

View File

@ -6,6 +6,7 @@ import Card from "@components/Card";
import { SettingsPageHeader } from "@components/SettingsPageheader";
import notifications from "@/notifications";
import LoadingSpinner from "@/components/LoadingSpinner";
import { logger } from "@/log";
import { useJsonRpc } from "../../hooks/useJsonRpc";
@ -53,7 +54,7 @@ export function ATXPowerControl() {
// Start long press timer
const timer = setTimeout(() => {
// Send long press action
console.log("Sending long press ATX power action");
logger.info("Sending long press ATX power action");
send("setATXPowerAction", { action: "power-long" }, resp => {
if ("error" in resp) {
notifications.error(
@ -74,7 +75,7 @@ export function ATXPowerControl() {
setPowerPressTimer(null);
// Send short press action
console.log("Sending short press ATX power action");
logger.info("Sending short press ATX power action");
send("setATXPowerAction", { action: "power-short" }, resp => {
if ("error" in resp) {
notifications.error(

View File

@ -69,7 +69,7 @@ export function SerialConsole() {
text="Open Console"
onClick={() => {
setTerminalType("serial");
console.log("Opening serial console with settings: ", settings);
logger.info("Opening serial console with settings: ", settings);
}}
/>
</div>

View File

@ -12,7 +12,7 @@ import { useHidStore, useRTCStore, useUiStore, useSettingsStore } from "@/hooks/
import { keys, modifiers } from "@/keyboardMappings";
import { layouts, chars } from "@/keyboardLayouts";
import notifications from "@/notifications";
import { logger } from "@/log";
const hidKeyboardPayload = (keys: number[], modifier: number) => {
return { keys, modifier };
};
@ -95,7 +95,7 @@ export default function PasteModal() {
}
}
} catch (error) {
console.error(error);
logger.error("Failed to paste text", error);
notifications.error("Failed to paste text");
}
}, [rpcDataChannel?.readyState, send, setDisableVideoFocusTrap, setPasteMode, keyboardLayout]);

View File

@ -6,6 +6,7 @@ import { SettingsPageHeader } from "@components/SettingsPageheader";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { useRTCStore, useUiStore } from "@/hooks/stores";
import notifications from "@/notifications";
import { logger } from "@/log";
import EmptyStateCard from "./EmptyStateCard";
import DeviceList, { StoredDevice } from "./DeviceList";
@ -56,7 +57,7 @@ export default function WakeOnLanModal() {
if ("result" in resp) {
setStoredDevices(resp.result as StoredDevice[]);
} else {
console.error("Failed to load Wake-on-LAN devices:", resp.error);
logger.error("Failed to load Wake-on-LAN devices:", resp.error);
}
});
}, [send, setStoredDevices]);
@ -72,7 +73,7 @@ export default function WakeOnLanModal() {
send("setWakeOnLanDevices", { params: { devices: updatedDevices } }, resp => {
if ("error" in resp) {
console.error("Failed to update Wake-on-LAN devices:", resp.error);
logger.error("Failed to update Wake-on-LAN devices:", resp.error);
} else {
syncStoredDevices();
}
@ -85,10 +86,10 @@ export default function WakeOnLanModal() {
(name: string, macAddress: string) => {
if (!name || !macAddress) return;
const updatedDevices = [...storedDevices, { name, macAddress }];
console.log("updatedDevices", updatedDevices);
logger.info("updatedDevices", updatedDevices);
send("setWakeOnLanDevices", { params: { devices: updatedDevices } }, resp => {
if ("error" in resp) {
console.error("Failed to add Wake-on-LAN device:", resp.error);
logger.error("Failed to add Wake-on-LAN device:", { error: resp.error });
setAddDeviceErrorMessage("Failed to add device");
} else {
setShowAddForm(false);

View File

@ -6,6 +6,7 @@ import {
MAX_TOTAL_MACROS,
MAX_KEYS_PER_STEP,
} from "@/constants/macros";
import { logger } from "@/log";
// Define the JsonRpc types for better type checking
interface JsonRpcResponse {
@ -744,7 +745,7 @@ export const useNetworkStateStore = create<NetworkState>((set, get) => ({
setDhcpLeaseExpiry: (expiry: Date) => {
const lease = get().dhcp_lease;
if (!lease) {
console.warn("No lease found");
logger.warn("No lease found");
return;
}
@ -807,7 +808,7 @@ export const useMacrosStore = create<MacrosState>((set, get) => ({
const { sendFn } = get();
if (!sendFn) {
console.warn("JSON-RPC send function not available.");
logger.warn("JSON-RPC send function not available.");
return;
}
@ -817,7 +818,7 @@ export const useMacrosStore = create<MacrosState>((set, get) => ({
await new Promise<void>((resolve, reject) => {
sendFn("getKeyboardMacros", {}, response => {
if (response.error) {
console.error("Error loading macros:", response.error);
logger.error("Error loading macros:", response.error);
reject(new Error(response.error.message));
return;
}
@ -842,7 +843,7 @@ export const useMacrosStore = create<MacrosState>((set, get) => ({
});
});
} catch (error) {
console.error("Failed to load macros:", error);
logger.error("Failed to load macros:", error);
} finally {
set({ loading: false });
}
@ -851,18 +852,18 @@ export const useMacrosStore = create<MacrosState>((set, get) => ({
saveMacros: async (macros: KeySequence[]) => {
const { sendFn } = get();
if (!sendFn) {
console.warn("JSON-RPC send function not available.");
logger.warn("JSON-RPC send function not available.");
throw new Error("JSON-RPC send function not available");
}
if (macros.length > MAX_TOTAL_MACROS) {
console.error(`Cannot save: exceeded maximum of ${MAX_TOTAL_MACROS} macros`);
logger.error(`Cannot save: exceeded maximum of ${MAX_TOTAL_MACROS} macros`);
throw new Error(`Cannot save: exceeded maximum of ${MAX_TOTAL_MACROS} macros`);
}
for (const macro of macros) {
if (macro.steps.length > MAX_STEPS_PER_MACRO) {
console.error(
logger.error(
`Cannot save: macro "${macro.name}" exceeds maximum of ${MAX_STEPS_PER_MACRO} steps`,
);
throw new Error(
@ -873,7 +874,7 @@ export const useMacrosStore = create<MacrosState>((set, get) => ({
for (let i = 0; i < macro.steps.length; i++) {
const step = macro.steps[i];
if (step.keys && step.keys.length > MAX_KEYS_PER_STEP) {
console.error(
logger.error(
`Cannot save: macro "${macro.name}" step ${i + 1} exceeds maximum of ${MAX_KEYS_PER_STEP} keys`,
);
throw new Error(
@ -902,7 +903,7 @@ export const useMacrosStore = create<MacrosState>((set, get) => ({
});
if (response.error) {
console.error("Error saving macros:", response.error);
logger.error("Error saving macros:", response.error);
const errorMessage =
typeof response.error.data === "string"
? response.error.data
@ -913,7 +914,7 @@ export const useMacrosStore = create<MacrosState>((set, get) => ({
// Only update the store if the request was successful
set({ macros: macrosWithSortOrder });
} catch (error) {
console.error("Failed to save macros:", error);
logger.error("Failed to save macros:", error);
throw error;
} finally {
set({ loading: false });

View File

@ -1,6 +1,8 @@
import { useNavigate, useParams, NavigateOptions } from "react-router-dom";
import { useCallback, useMemo } from "react";
import { logger } from "@/log";
import { isOnDevice } from "../main";
/**
@ -21,7 +23,7 @@ export function getDeviceUiPath(path: string, deviceId?: string): string {
return normalizedPath;
} else {
if (!deviceId) {
console.error("No device ID provided when generating path in cloud mode");
logger.error("No device ID provided when generating path in cloud mode");
throw new Error("Device ID is required for cloud mode path generation");
}
return `/devices/${deviceId}${normalizedPath}`;

View File

@ -1,7 +1,7 @@
import { useCallback, useEffect } from "react";
import { useRTCStore } from "@/hooks/stores";
import { jsonRpcLogger } from "@/log";
export interface JsonRpcRequest {
jsonrpc: string;
method: string;
@ -61,7 +61,7 @@ export function useJsonRpc(onRequest?: (payload: JsonRpcRequest) => void) {
return;
}
if ("error" in payload) console.error(payload.error);
if ("error" in payload) jsonRpcLogger.error(payload.error);
if (!payload.id) return;
const callback = callbackStore.get(payload.id);

View File

@ -16,6 +16,7 @@ import { User } from "@/hooks/stores";
import { checkAuth } from "@/main";
import Fieldset from "@components/Fieldset";
import { CLOUD_API } from "@/ui.config";
import { logger } from "@/log";
interface LoaderData {
device: { id: string; name: string; user: { googleId: string } };
@ -37,7 +38,7 @@ const action = async ({ request }: ActionFunctionArgs) => {
return { message: "There was an error renaming your device. Please try again." };
}
} catch (e) {
console.error(e);
logger.error("Error deregistering device", e);
return { message: "There was an error renaming your device. Please try again." };
}
@ -61,7 +62,7 @@ const loader = async ({ params }: LoaderFunctionArgs) => {
return { device, user };
} catch (e) {
console.error(e);
logger.error("Error deregistering device", e);
return { devices: [] };
}
};

View File

@ -26,6 +26,7 @@ import ArchIcon from "@/assets/arch-icon.png";
import NetBootIcon from "@/assets/netboot-icon.svg";
import Fieldset from "@/components/Fieldset";
import { DEVICE_API } from "@/ui.config";
import { logger } from "@/log";
import { useJsonRpc } from "../hooks/useJsonRpc";
import notifications from "../notifications";
@ -86,7 +87,7 @@ export function Dialog({ onClose }: { onClose: () => void }) {
}
function handleUrlMount(url: string, mode: RemoteVirtualMediaState["mode"]) {
console.log(`Mounting ${url} as ${mode}`);
logger.info(`Mounting ${url} as ${mode}`);
setMountInProgress(true);
send("mountWithHTTP", { url, mode }, async resp => {
@ -105,7 +106,7 @@ export function Dialog({ onClose }: { onClose: () => void }) {
}
function handleStorageMount(fileName: string, mode: RemoteVirtualMediaState["mode"]) {
console.log(`Mounting ${fileName} as ${mode}`);
logger.info(`Mounting ${fileName} as ${mode}`);
setMountInProgress(true);
send("mountWithStorage", { filename: fileName, mode }, async resp => {
@ -132,7 +133,7 @@ export function Dialog({ onClose }: { onClose: () => void }) {
}
function handleBrowserMount(file: File, mode: RemoteVirtualMediaState["mode"]) {
console.log(`Mounting ${file.name} as ${mode}`);
logger.info(`Mounting ${file.name} as ${mode}`);
setMountInProgress(true);
send(
@ -419,7 +420,7 @@ function BrowserFileView({
const handleMount = () => {
if (selectedFile) {
console.log(`Mounting ${selectedFile.name} as ${setUsbMode}`);
logger.info(`Mounting ${selectedFile.name} as ${setUsbMode}`);
onMountFile(selectedFile, usbMode);
}
};
@ -756,7 +757,7 @@ function DeviceFileView({
}, [syncStorage]);
function handleDeleteFile(file: { name: string; size: string; createdAt: string }) {
console.log("Deleting file:", file);
logger.info("Deleting file:", file);
send("deleteStorageFile", { filename: file.name }, res => {
if ("error" in res) {
notifications.error(`Error deleting file: ${res.error}`);
@ -986,6 +987,8 @@ function UploadFileView({
onCancelUpload: () => void;
incompleteFileName?: string;
}) {
const l = logger.getSubLogger({ name: "file-upload" });
const [uploadState, setUploadState] = useState<"idle" | "uploading" | "success">(
"idle",
);
@ -1002,7 +1005,7 @@ function UploadFileView({
useEffect(() => {
const ref = rtcDataChannelRef.current;
return () => {
console.log("unmounting");
logger.info("unmounting");
if (ref) {
ref.onopen = null;
ref.onerror = null;
@ -1023,10 +1026,10 @@ function UploadFileView({
.peerConnection?.createDataChannel(dataChannel);
if (!rtcDataChannel) {
console.error("Failed to create data channel for file upload");
l.error("Failed to create data channel for file upload");
notifications.error("Failed to create data channel for file upload");
setUploadState("idle");
console.log("Upload state set to 'idle'");
l.info("Upload state set to 'idle'");
return;
}
@ -1072,7 +1075,7 @@ function UploadFileView({
lastUploadedBytes = AlreadyUploadedBytes;
lastUpdateTime = now;
} catch (e) {
console.error("Error processing RTC Data channel message:", e);
l.error("Error processing RTC Data channel message:", e);
}
};
@ -1099,24 +1102,24 @@ function UploadFileView({
}
offset += buffer.byteLength;
console.log(`Chunk sent: ${offset} / ${file.size} bytes`);
l.info(`Chunk sent: ${offset} / ${file.size} bytes`);
sendNextChunk();
});
};
sendNextChunk();
rtcDataChannel.onbufferedamountlow = () => {
console.log("RTC Data channel buffered amount low");
l.info("RTC Data channel buffered amount low");
pauseSending = false; // Now the data channel is ready to send more data
sendNextChunk();
};
};
rtcDataChannel.onerror = error => {
console.error("RTC Data channel error:", error);
l.error("RTC Data channel error:", error);
notifications.error(`Upload failed: ${error}`);
setUploadState("idle");
console.log("Upload state set to 'idle'");
l.info("Upload state set to 'idle'");
};
}
@ -1169,14 +1172,14 @@ function UploadFileView({
if (xhr.status === 200) {
setUploadState("success");
} else {
console.error("Upload error:", xhr.statusText);
l.error("Upload error:", xhr.statusText);
setUploadError(xhr.statusText);
setUploadState("idle");
}
};
xhr.onerror = () => {
console.error("XHR error:", xhr.statusText);
l.error("XHR error:", xhr.statusText);
setUploadError(xhr.statusText);
setUploadState("idle");
};
@ -1205,19 +1208,19 @@ function UploadFileView({
}
setFileError(null);
console.log(`File selected: ${file.name}, size: ${file.size} bytes`);
l.info(`File selected: ${file.name}, size: ${file.size} bytes`);
setUploadedFileName(file.name);
setUploadedFileSize(file.size);
setUploadState("uploading");
console.log("Upload state set to 'uploading'");
l.info("Upload state set to 'uploading'");
send("startStorageFileUpload", { filename: file.name, size: file.size }, resp => {
console.log("startStorageFileUpload response:", resp);
l.info("startStorageFileUpload response:", resp);
if ("error" in resp) {
console.error("Upload error:", resp.error.message);
l.error("Upload error:", resp.error.message);
setUploadError(resp.error.data || resp.error.message);
setUploadState("idle");
console.log("Upload state set to 'idle'");
l.info("Upload state set to 'idle'");
return;
}
@ -1226,7 +1229,7 @@ function UploadFileView({
dataChannel: string;
};
console.log(
l.info(
`Already uploaded bytes: ${alreadyUploadedBytes}, Data channel: ${dataChannel}`,
);

View File

@ -17,6 +17,7 @@ import { User } from "@/hooks/stores";
import { checkAuth } from "@/main";
import Fieldset from "@components/Fieldset";
import { CLOUD_API } from "@/ui.config";
import { logger } from "@/log";
import api from "../api";
@ -41,7 +42,7 @@ const action = async ({ params, request }: ActionFunctionArgs) => {
return { message: "There was an error renaming your device. Please try again." };
}
} catch (e) {
console.error(e);
logger.error("Error renaming device", e);
return { message: "There was an error renaming your device. Please try again." };
}
@ -65,7 +66,7 @@ const loader = async ({ params }: LoaderFunctionArgs) => {
return { device, user };
} catch (e) {
console.error(e);
logger.error("Error renaming device", e);
return { devices: [] };
}
};

View File

@ -15,6 +15,7 @@ import { DEVICE_API } from "@/ui.config";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { isOnDevice } from "@/main";
import { TextAreaWithLabel } from "@components/TextArea";
import { logger } from "@/log";
import { LocalDevice } from "./devices.$id";
import { SettingsItem } from "./devices.$id.settings";
@ -57,7 +58,7 @@ export default function SettingsAccessIndexRoute() {
const getCloudState = useCallback(() => {
send("getCloudState", {}, resp => {
if ("error" in resp) return console.error(resp.error);
if ("error" in resp) return logger.error("Error getting cloud state", resp.error);
const cloudState = resp.result as CloudState;
setAdopted(cloudState.connected);
setCloudApiUrl(cloudState.url);
@ -78,7 +79,7 @@ export default function SettingsAccessIndexRoute() {
const getTLSState = useCallback(() => {
send("getTLSState", {}, resp => {
if ("error" in resp) return console.error(resp.error);
if ("error" in resp) return logger.error("Error getting TLS state", resp.error);
const tlsState = resp.result as TLSState;
setTlsMode(tlsState.mode);
@ -199,7 +200,7 @@ export default function SettingsAccessIndexRoute() {
getTLSState();
send("getDeviceID", {}, async resp => {
if ("error" in resp) return console.error(resp.error);
if ("error" in resp) return logger.error("Error getting device ID", resp.error);
setDeviceId(resp.result as string);
});
}, [send, getCloudState, getTLSState]);

View File

@ -6,6 +6,7 @@ import { InputFieldWithLabel } from "@/components/InputField";
import api from "@/api";
import { useLocalAuthModalStore } from "@/hooks/stores";
import { useDeviceUiNavigation } from "@/hooks/useAppNavigation";
import { logger } from "@/log";
export default function SecurityAccessLocalAuthRoute() {
const { setModalView } = useLocalAuthModalStore();
@ -54,7 +55,7 @@ export function Dialog({ onClose }: { onClose: () => void }) {
setError(data.error || "An error occurred while setting the password");
}
} catch (error) {
console.error(error);
logger.error("An error occurred while setting the password", error);
setError("An error occurred while setting the password");
}
};
@ -94,7 +95,7 @@ export function Dialog({ onClose }: { onClose: () => void }) {
setError(data.error || "An error occurred while changing the password");
}
} catch (error) {
console.error(error);
logger.error("An error occurred while changing the password", error);
setError("An error occurred while changing the password");
}
};
@ -116,7 +117,7 @@ export function Dialog({ onClose }: { onClose: () => void }) {
setError(data.error || "An error occurred while disabling the password");
}
} catch (error) {
console.error(error);
logger.error("An error occurred while disabling the password", error);
setError("An error occurred while disabling the password");
}
};

View File

@ -9,6 +9,7 @@ import { UpdateState, useDeviceStore, useUpdateStore } from "@/hooks/stores";
import notifications from "@/notifications";
import LoadingSpinner from "@/components/LoadingSpinner";
import { useDeviceUiNavigation } from "@/hooks/useAppNavigation";
import { logger } from "@/log";
export default function SettingsGeneralUpdateRoute() {
const navigate = useNavigate();
@ -184,7 +185,7 @@ function LoadingState({
})
.catch(error => {
if (!signal.aborted) {
console.error("LoadingState: Error fetching version info", error);
logger.error("LoadingState: Error fetching version info", error);
}
});
@ -240,7 +241,7 @@ function UpdatingDeviceState({
return 0;
}
console.log(
logger.info(
`For ${type}:\n` +
` Download Progress: ${downloadProgress}% (${otaState[`${type}DownloadProgress`]})\n` +
` Update Progress: ${updateProgress}% (${otaState[`${type}UpdateProgress`]})\n` +

View File

@ -22,6 +22,7 @@ import { SettingsPageHeader } from "@/components/SettingsPageheader";
import Fieldset from "@/components/Fieldset";
import { ConfirmDialog } from "@/components/ConfirmDialog";
import notifications from "@/notifications";
import { logger } from "@/log";
import Ipv6NetworkCard from "../components/Ipv6NetworkCard";
import EmptyCard from "../components/EmptyCard";
@ -29,7 +30,6 @@ import AutoHeight from "../components/AutoHeight";
import DhcpLeaseCard from "../components/DhcpLeaseCard";
import { SettingsItem } from "./devices.$id.settings";
dayjs.extend(relativeTime);
const defaultNetworkSettings: NetworkSettings = {
@ -105,7 +105,7 @@ export default function SettingsNetworkRoute() {
setNetworkSettingsLoaded(false);
send("getNetworkSettings", {}, resp => {
if ("error" in resp) return;
console.log(resp.result);
logger.trace("getNetworkSettings result:", resp.result);
setNetworkSettings(resp.result as NetworkSettings);
if (!firstNetworkSettings.current) {
@ -118,7 +118,7 @@ export default function SettingsNetworkRoute() {
const getNetworkState = useCallback(() => {
send("getNetworkState", {}, resp => {
if ("error" in resp) return;
console.log(resp.result);
logger.trace("getNetworkState result:", resp.result);
setNetworkState(resp.result as NetworkState);
});
}, [send, setNetworkState]);

View File

@ -20,11 +20,11 @@ import { LinkButton } from "@/components/Button";
import LoadingSpinner from "@/components/LoadingSpinner";
import { useUiStore } from "@/hooks/stores";
import useKeyboard from "@/hooks/useKeyboard";
import { logger } from "@/log";
import { FeatureFlag } from "../components/FeatureFlag";
import { cx } from "../cva.config";
/* TODO: Migrate to using URLs instead of the global state. To simplify the refactoring, we'll keep the global state for now. */
export default function SettingsRoute() {
const location = useLocation();
@ -73,7 +73,7 @@ export default function SettingsRoute() {
// For some reason, the focus trap is not disabled immediately
// so we need to blur the active element
(document.activeElement as HTMLElement)?.blur();
console.log("Just disabled focus trap");
logger.info("Just disabled focus trap");
}, 300);
return () => {

View File

@ -28,6 +28,7 @@ import {
useNetworkStateStore,
User,
useRTCStore,
useSettingsStore,
useUiStore,
useUpdateStore,
useVideoStore,
@ -40,6 +41,7 @@ import ConnectionStatsSidebar from "@/components/sidebar/connectionStats";
import { JsonRpcRequest, useJsonRpc } from "@/hooks/useJsonRpc";
import Terminal from "@components/Terminal";
import { CLOUD_API, DEVICE_API } from "@/ui.config";
import { logger, enableDebugMode, disableDebugMode } from "@/log";
import UpdateInProgressStatusCard from "../components/UpdateInProgressStatusCard";
import api from "../api";
@ -130,6 +132,16 @@ export default function KvmIdRoute() {
const sidebarView = useUiStore(state => state.sidebarView);
const [queryParams, setQueryParams] = useSearchParams();
// Enable dev mode if the user is in debug mode
const isDebugMode = useSettingsStore(state => state.debugMode);
useEffect(() => {
if (isDebugMode) {
enableDebugMode();
} else {
disableDebugMode();
}
}, [isDebugMode]);
const setIsTurnServerInUse = useRTCStore(state => state.setTurnServerInUse);
const peerConnection = useRTCStore(state => state.peerConnection);
const setPeerConnectionState = useRTCStore(state => state.setPeerConnectionState);
@ -151,7 +163,7 @@ export default function KvmIdRoute() {
const [loadingMessage, setLoadingMessage] = useState("Connecting to device...");
const cleanupAndStopReconnecting = useCallback(
function cleanupAndStopReconnecting() {
console.log("Closing peer connection");
logger.info("Closing peer connection");
setConnectionFailed(true);
if (peerConnection) {
@ -187,15 +199,14 @@ export default function KvmIdRoute() {
) {
setLoadingMessage("Setting remote description");
const l = logger.getSubLogger({ name: "setRemoteSessionDescription" });
try {
await pc.setRemoteDescription(new RTCSessionDescription(remoteDescription));
console.log("[setRemoteSessionDescription] Remote description set successfully");
l.info("Remote description set successfully");
setLoadingMessage("Establishing secure connection...");
} catch (error) {
console.error(
"[setRemoteSessionDescription] Failed to set remote description:",
error,
);
l.error("Failed to set remote description", { error });
cleanupAndStopReconnecting();
return;
}
@ -207,12 +218,12 @@ export default function KvmIdRoute() {
// When vivaldi has disabled "Broadcast IP for Best WebRTC Performance", this never connects
if (pc.sctp?.state === "connected") {
console.log("[setRemoteSessionDescription] Remote description set");
l.info("Remote description set");
clearInterval(checkInterval);
setLoadingMessage("Connection established");
} else if (attempts >= 10) {
console.log(
"[setRemoteSessionDescription] Failed to establish connection after 10 attempts",
l.error(
"Failed to establish connection after 10 attempts",
{
connectionState: pc.connectionState,
iceConnectionState: pc.iceConnectionState,
@ -221,7 +232,7 @@ export default function KvmIdRoute() {
cleanupAndStopReconnecting();
clearInterval(checkInterval);
} else {
console.log("[setRemoteSessionDescription] Waiting for connection, state:", {
l.info("[setRemoteSessionDescription] Waiting for connection, state:", {
connectionState: pc.connectionState,
iceConnectionState: pc.iceConnectionState,
});
@ -236,6 +247,7 @@ export default function KvmIdRoute() {
const makingOffer = useRef(false);
const wsProtocol = window.location.protocol === "https:" ? "wss:" : "ws:";
const wsLogger = logger.getSubLogger({ name: "websocket" });
const { sendMessage, getWebSocket } = useWebSocket(
isOnDevice
@ -247,27 +259,27 @@ export default function KvmIdRoute() {
reconnectAttempts: 15,
reconnectInterval: 1000,
onReconnectStop: () => {
console.log("Reconnect stopped");
wsLogger.info("Reconnect stopped");
cleanupAndStopReconnecting();
},
shouldReconnect(event) {
console.log("[Websocket] shouldReconnect", event);
wsLogger.info("shouldReconnect", event);
// TODO: Why true?
return true;
},
onClose(event) {
console.log("[Websocket] onClose", event);
wsLogger.info("onClose", event);
// We don't want to close everything down, we wait for the reconnect to stop instead
},
onError(event) {
console.log("[Websocket] onError", event);
wsLogger.error("onError", event);
// We don't want to close everything down, we wait for the reconnect to stop instead
},
onOpen() {
console.log("[Websocket] onOpen");
wsLogger.info("onOpen");
},
onMessage: message => {
@ -289,18 +301,18 @@ export default function KvmIdRoute() {
const parsedMessage = JSON.parse(message.data);
if (parsedMessage.type === "device-metadata") {
const { deviceVersion } = parsedMessage.data;
console.log("[Websocket] Received device-metadata message");
console.log("[Websocket] Device version", deviceVersion);
wsLogger.info("Received device-metadata message");
wsLogger.info("Device version", deviceVersion);
// If the device version is not set, we can assume the device is using the legacy signaling
if (!deviceVersion) {
console.log("[Websocket] Device is using legacy signaling");
wsLogger.info("Device is using legacy signaling");
// Now we don't need the websocket connection anymore, as we've established that we need to use the legacy signaling
// which does everything over HTTP(at least from the perspective of the client)
isLegacySignalingEnabled.current = true;
getWebSocket()?.close();
} else {
console.log("[Websocket] Device is using new signaling");
wsLogger.info("Device is using new signaling");
isLegacySignalingEnabled.current = false;
}
setupPeerConnection();
@ -308,7 +320,7 @@ export default function KvmIdRoute() {
if (!peerConnection) return;
if (parsedMessage.type === "answer") {
console.log("[Websocket] Received answer");
wsLogger.info("Received answer");
const readyForOffer =
// If we're making an offer, we don't want to accept an answer
!makingOffer &&
@ -322,10 +334,7 @@ export default function KvmIdRoute() {
// Set so we don't accept an answer while we're setting the remote description
isSettingRemoteAnswerPending.current = parsedMessage.type === "answer";
console.log(
"[Websocket] Setting remote answer pending",
isSettingRemoteAnswerPending.current,
);
wsLogger.info("Setting remote answer pending", isSettingRemoteAnswerPending.current);
const sd = atob(parsedMessage.data);
const remoteSessionDescription = JSON.parse(sd);
@ -338,8 +347,8 @@ export default function KvmIdRoute() {
// Reset the remote answer pending flag
isSettingRemoteAnswerPending.current = false;
} else if (parsedMessage.type === "new-ice-candidate") {
console.log("[Websocket] Received new-ice-candidate");
const candidate = parsedMessage.data;
wsLogger.info("Received new-ice-candidate", { candidate});
peerConnection.addIceCandidate(candidate);
}
},
@ -366,7 +375,7 @@ export default function KvmIdRoute() {
// In device mode, old devices wont server this JS, and on newer devices legacy mode wont be enabled
const sessionUrl = `${CLOUD_API}/webrtc/session`;
console.log("Trying to get remote session description");
logger.info("Trying to get remote session description");
setLoadingMessage(
`Getting remote session description... ${signalingAttempts.current > 0 ? `(attempt ${signalingAttempts.current + 1})` : ""}`,
);
@ -379,12 +388,12 @@ export default function KvmIdRoute() {
const json = await res.json();
if (res.status === 401) return navigate(isOnDevice ? "/login-local" : "/login");
if (!res.ok) {
console.error("Error getting SDP", { status: res.status, json });
logger.error("Error getting SDP", { status: res.status, json });
cleanupAndStopReconnecting();
return;
}
console.log("Successfully got Remote Session Description. Setting.");
logger.info("Successfully got Remote Session Description. Setting.");
setLoadingMessage("Setting remote session description...");
const decodedSd = atob(json.sd);
@ -395,13 +404,15 @@ export default function KvmIdRoute() {
);
const setupPeerConnection = useCallback(async () => {
console.log("[setupPeerConnection] Setting up peer connection");
const l = logger.getSubLogger({ name: "setupPeerConnection" });
l.info("Setting up peer connection");
setConnectionFailed(false);
setLoadingMessage("Connecting to device...");
let pc: RTCPeerConnection;
try {
console.log("[setupPeerConnection] Creating peer connection");
l.info("Creating peer connection");
setLoadingMessage("Creating peer connection...");
pc = new RTCPeerConnection({
// We only use STUN or TURN servers if we're in the cloud
@ -411,10 +422,10 @@ export default function KvmIdRoute() {
});
setPeerConnectionState(pc.connectionState);
console.log("[setupPeerConnection] Peer connection created", pc);
l.info("Peer connection created", pc);
setLoadingMessage("Setting up connection to device...");
} catch (e) {
console.error(`[setupPeerConnection] Error creating peer connection: ${e}`);
l.error(`Error creating peer connection: ${e}`);
setTimeout(() => {
cleanupAndStopReconnecting();
}, 1000);
@ -423,13 +434,13 @@ export default function KvmIdRoute() {
// Set up event listeners and data channels
pc.onconnectionstatechange = () => {
console.log("[setupPeerConnection] Connection state changed", pc.connectionState);
l.info("Connection state changed", pc.connectionState);
setPeerConnectionState(pc.connectionState);
};
pc.onnegotiationneeded = async () => {
try {
console.log("[setupPeerConnection] Creating offer");
l.info("Creating offer");
makingOffer.current = true;
const offer = await pc.createOffer();
@ -439,13 +450,10 @@ export default function KvmIdRoute() {
if (isNewSignalingEnabled) {
sendWebRTCSignal("offer", { sd: sd });
} else {
console.log("Legacy signanling. Waiting for ICE Gathering to complete...");
l.info("Legacy signanling. Waiting for ICE Gathering to complete...");
}
} catch (e) {
console.error(
`[setupPeerConnection] Error creating offer: ${e}`,
new Date().toISOString(),
);
l.error(`Error creating offer`, { date: new Date().toISOString(), error: e });
cleanupAndStopReconnecting();
} finally {
makingOffer.current = false;
@ -461,7 +469,7 @@ export default function KvmIdRoute() {
pc.onicegatheringstatechange = event => {
const pc = event.currentTarget as RTCPeerConnection;
if (pc.iceGatheringState === "complete") {
console.log("ICE Gathering completed");
l.info("ICE Gathering completed");
setLoadingMessage("ICE Gathering completed");
if (isLegacySignalingEnabled.current) {
@ -469,7 +477,7 @@ export default function KvmIdRoute() {
legacyHTTPSignaling(pc);
}
} else if (pc.iceGatheringState === "gathering") {
console.log("ICE Gathering Started");
l.info("ICE Gathering Started");
setLoadingMessage("Gathering ICE candidates...");
}
};
@ -506,7 +514,7 @@ export default function KvmIdRoute() {
useEffect(() => {
if (peerConnectionState === "failed") {
console.log("Connection failed, closing peer connection");
logger.info("Connection failed, closing peer connection");
cleanupAndStopReconnecting();
}
}, [peerConnectionState, cleanupAndStopReconnecting]);
@ -609,13 +617,13 @@ export default function KvmIdRoute() {
}
if (resp.method === "networkState") {
console.log("Setting network state", resp.params);
logger.info("Setting network state", resp.params);
setNetworkState(resp.params as NetworkState);
}
if (resp.method === "keyboardLedState") {
const ledState = resp.params as KeyboardLedState;
console.log("Setting keyboard led state", ledState);
logger.info("Setting keyboard led state", ledState);
setKeyboardLedState(ledState);
setKeyboardLedStateSyncAvailable(true);
}
@ -660,20 +668,20 @@ export default function KvmIdRoute() {
useEffect(() => {
if (rpcDataChannel?.readyState !== "open") return;
if (keyboardLedState !== undefined) return;
console.log("Requesting keyboard led state");
logger.info("Requesting keyboard led state");
send("getKeyboardLedState", {}, resp => {
if ("error" in resp) {
// -32601 means the method is not supported
if (resp.error.code === -32601) {
setKeyboardLedStateSyncAvailable(false);
console.error("Failed to get keyboard led state, disabling sync", resp.error);
logger.error("Failed to get keyboard led state, disabling sync", resp.error);
} else {
console.error("Failed to get keyboard led state", resp.error);
logger.error("Failed to get keyboard led state", resp.error);
}
return;
}
console.log("Keyboard led state", resp.result);
logger.info("Keyboard led state", resp.result);
setKeyboardLedState(resp.result as KeyboardLedState);
setKeyboardLedStateSyncAvailable(true);
});
@ -691,7 +699,7 @@ export default function KvmIdRoute() {
useEffect(() => {
if (!diskChannel || !file) return;
diskChannel.onmessage = async e => {
console.log("Received", e.data);
logger.info("Received", e.data);
const data = JSON.parse(e.data);
const blob = file.slice(data.start, data.end);
const buf = await blob.arrayBuffer();

View File

@ -10,7 +10,7 @@ import { LinkButton } from "@components/Button";
import { User } from "@/hooks/stores";
import { checkAuth } from "@/main";
import { CLOUD_API } from "@/ui.config";
import { logger } from "@/log";
interface LoaderData {
devices: { id: string; name: string; online: boolean; lastSeen: string }[];
user: User;
@ -29,7 +29,7 @@ const loader = async () => {
const { devices } = await res.json();
return { devices, user };
} catch (e) {
console.error(e);
logger.error("Error loading devices", e);
return { devices: [] };
}
};

View File

@ -11,12 +11,12 @@ import { Button } from "@components/Button";
import LogoBlueIcon from "@/assets/logo-blue.png";
import LogoWhiteIcon from "@/assets/logo-white.svg";
import { DEVICE_API } from "@/ui.config";
import { logger } from "@/log";
import api from "../api";
import ExtLink from "../components/ExtLink";
import { DeviceStatus } from "./welcome-local";
const loader = async () => {
const res = await api
.GET(`${DEVICE_API}/device/status`)
@ -44,7 +44,7 @@ const action = async ({ request }: ActionFunctionArgs) => {
return { error: "Invalid password" };
}
} catch (error) {
console.error(error);
logger.error("An error occurred while logging in", error);
return { error: "An error occurred while logging in" };
}
};

View File

@ -7,13 +7,13 @@ import { Button } from "@components/Button";
import LogoBlueIcon from "@/assets/logo-blue.png";
import LogoWhiteIcon from "@/assets/logo-white.svg";
import { DEVICE_API } from "@/ui.config";
import { logger } from "@/log";
import { GridCard } from "../components/Card";
import { cx } from "../cva.config";
import api from "../api";
import { DeviceStatus } from "./welcome-local";
const loader = async () => {
const res = await api
.GET(`${DEVICE_API}/device/status`)
@ -39,7 +39,7 @@ const action = async ({ request }: ActionFunctionArgs) => {
});
return redirect("/");
} catch (error) {
console.error("Error setting authentication mode:", error);
logger.error("Error setting authentication mode:", error);
return { error: "An error occurred while setting the authentication mode" };
}
}

View File

@ -10,11 +10,11 @@ import { Button } from "@components/Button";
import LogoBlueIcon from "@/assets/logo-blue.png";
import LogoWhiteIcon from "@/assets/logo-white.svg";
import { DEVICE_API } from "@/ui.config";
import { logger } from "@/log";
import api from "../api";
import { DeviceStatus } from "./welcome-local";
const loader = async () => {
const res = await api
.GET(`${DEVICE_API}/device/status`)
@ -45,7 +45,7 @@ const action = async ({ request }: ActionFunctionArgs) => {
return { error: "Failed to set password" };
}
} catch (error) {
console.error("Error setting password:", error);
logger.error("Error setting password:", error);
return { error: "An error occurred while setting the password" };
}
};