1
0
Fork 0
mirror of https://gitlab.com/futo-org/fcast.git synced 2025-06-24 21:25:23 +00:00

Receivers: Added unified logger module

This commit is contained in:
Michael Hollister 2025-05-01 10:37:21 -05:00
parent 7f9d7939bc
commit b24b3f0c55
17 changed files with 351 additions and 117 deletions

View file

@ -7,6 +7,7 @@ let uiUpdateCallbacks = {
onConnect: null, onConnect: null,
onDisconnect: null, onDisconnect: null,
} }
const logger = window.targetAPI.logger;
// Window might be re-created while devices are still connected // Window might be re-created while devices are still connected
export function setUiUpdateCallbacks(callbacks: any) { export function setUiUpdateCallbacks(callbacks: any) {
@ -27,12 +28,12 @@ window.targetAPI.onPing((_event, value: any) => onPingPong(value));
window.targetAPI.onPong((_event, value: any) => onPingPong(value)); window.targetAPI.onPong((_event, value: any) => onPingPong(value));
window.targetAPI.onConnect((_event, value: any) => { window.targetAPI.onConnect((_event, value: any) => {
console.log(`Device connected: ${JSON.stringify(value)}`); logger.info(`Device connected: ${JSON.stringify(value)}`);
connections.push(value.sessionId); connections.push(value.sessionId);
uiUpdateCallbacks.onConnect(connections); uiUpdateCallbacks.onConnect(connections);
}); });
window.targetAPI.onDisconnect((_event, value: any) => { window.targetAPI.onDisconnect((_event, value: any) => {
console.log(`Device disconnected: ${JSON.stringify(value)}`); logger.info(`Device disconnected: ${JSON.stringify(value)}`);
const index = connections.indexOf(value.sessionId); const index = connections.indexOf(value.sessionId);
if (index != -1) { if (index != -1) {
connections.splice(index, 1); connections.splice(index, 1);
@ -46,7 +47,7 @@ setInterval(() => {
for (const sessionId of connections) { for (const sessionId of connections) {
if (heartbeatRetries[sessionId] > 3) { if (heartbeatRetries[sessionId] > 3) {
console.warn(`Could not ping device with connection id ${sessionId}. Disconnecting...`); logger.warn(`Could not ping device with connection id ${sessionId}. Disconnecting...`);
window.targetAPI.disconnectDevice(sessionId); window.targetAPI.disconnectDevice(sessionId);
} }

View file

@ -1,5 +1,7 @@
import mdns from 'modules/mdns-js'; import mdns from 'modules/mdns-js';
import { Main, getComputerName } from 'src/Main'; import { Logger, LoggerType } from 'common/Logger';
import { getComputerName } from 'src/Main';
const logger = new Logger('DiscoveryService', LoggerType.BACKEND);
export class DiscoveryService { export class DiscoveryService {
private serviceTcp: any; private serviceTcp: any;
@ -11,13 +13,7 @@ export class DiscoveryService {
} }
const name = `FCast-${getComputerName()}`; const name = `FCast-${getComputerName()}`;
// Cannot reference Main during static class initialization logger.info(`Discovery service started: ${name}`);
// @ts-ignore
if (TARGET === 'webOS') {
console.log(`Discovery service started: ${name}`);
} else {
Main.logger.info(`Discovery service started: ${name}`);
}
this.serviceTcp = mdns.createAdvertisement(mdns.tcp('_fcast'), 46899, { name: name }); this.serviceTcp = mdns.createAdvertisement(mdns.tcp('_fcast'), 46899, { name: name });
this.serviceTcp.start(); this.serviceTcp.start();

View file

@ -1,10 +1,10 @@
import * as net from 'net'; import * as net from 'net';
import * as log4js from "modules/log4js";
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { Opcode, PlaybackErrorMessage, PlaybackUpdateMessage, PlayMessage, SeekMessage, SetSpeedMessage, SetVolumeMessage, VersionMessage, VolumeUpdateMessage } from 'common/Packets'; import { Opcode, PlaybackErrorMessage, PlaybackUpdateMessage, PlayMessage, SeekMessage, SetSpeedMessage, SetVolumeMessage, VersionMessage, VolumeUpdateMessage } from 'common/Packets';
import { Logger, LoggerType } from 'common/Logger';
import { WebSocket } from 'modules/ws'; import { WebSocket } from 'modules/ws';
import { v4 as uuidv4 } from 'modules/uuid'; import { v4 as uuidv4 } from 'modules/uuid';
const logger = log4js.getLogger(); const logger = new Logger('FCastSession', LoggerType.BACKEND);
enum SessionState { enum SessionState {
Idle = 0, Idle = 0,
@ -100,7 +100,7 @@ export class FCastSession {
return; return;
} }
logger.info(`${receivedBytes.length} bytes received`); logger.debug(`${receivedBytes.length} bytes received`);
switch (this.state) { switch (this.state) {
case SessionState.WaitingForLength: case SessionState.WaitingForLength:
@ -110,7 +110,7 @@ export class FCastSession {
this.handlePacketBytes(receivedBytes); this.handlePacketBytes(receivedBytes);
break; break;
default: default:
logger.info(`Data received is unhandled in current session state ${this.state}.`); logger.warn(`Data received is unhandled in current session state ${this.state}.`);
break; break;
} }
} }
@ -121,20 +121,20 @@ export class FCastSession {
receivedBytes.copy(this.buffer, this.bytesRead, 0, bytesToRead); receivedBytes.copy(this.buffer, this.bytesRead, 0, bytesToRead);
this.bytesRead += bytesToRead; this.bytesRead += bytesToRead;
logger.info(`handleLengthBytes: Read ${bytesToRead} bytes from packet`); logger.debug(`handleLengthBytes: Read ${bytesToRead} bytes from packet`);
if (this.bytesRead >= LENGTH_BYTES) { if (this.bytesRead >= LENGTH_BYTES) {
this.state = SessionState.WaitingForData; this.state = SessionState.WaitingForData;
this.packetLength = this.buffer.readUInt32LE(0); this.packetLength = this.buffer.readUInt32LE(0);
this.bytesRead = 0; this.bytesRead = 0;
logger.info(`Packet length header received from: ${this.packetLength}`); logger.debug(`Packet length header received from: ${this.packetLength}`);
if (this.packetLength > MAXIMUM_PACKET_LENGTH) { if (this.packetLength > MAXIMUM_PACKET_LENGTH) {
throw new Error(`Maximum packet length is 32kB: ${this.packetLength}`); throw new Error(`Maximum packet length is 32kB: ${this.packetLength}`);
} }
if (bytesRemaining > 0) { if (bytesRemaining > 0) {
logger.info(`${bytesRemaining} remaining bytes pushed to handlePacketBytes`); logger.debug(`${bytesRemaining} remaining bytes pushed to handlePacketBytes`);
this.handlePacketBytes(receivedBytes.slice(bytesToRead)); this.handlePacketBytes(receivedBytes.slice(bytesToRead));
} }
} }
@ -146,10 +146,10 @@ export class FCastSession {
receivedBytes.copy(this.buffer, this.bytesRead, 0, bytesToRead); receivedBytes.copy(this.buffer, this.bytesRead, 0, bytesToRead);
this.bytesRead += bytesToRead; this.bytesRead += bytesToRead;
logger.info(`handlePacketBytes: Read ${bytesToRead} bytes from packet`); logger.debug(`handlePacketBytes: Read ${bytesToRead} bytes from packet`);
if (this.bytesRead >= this.packetLength) { if (this.bytesRead >= this.packetLength) {
logger.info(`Packet finished receiving from of ${this.packetLength} bytes.`); logger.debug(`handlePacketBytes: Finished handling packet with ${this.packetLength} bytes. Total bytes read ${this.bytesRead}.`);
this.handleNextPacket(); this.handleNextPacket();
this.state = SessionState.WaitingForLength; this.state = SessionState.WaitingForLength;
@ -157,7 +157,7 @@ export class FCastSession {
this.bytesRead = 0; this.bytesRead = 0;
if (bytesRemaining > 0) { if (bytesRemaining > 0) {
logger.info(`${bytesRemaining} remaining bytes pushed to handleLengthBytes`); logger.debug(`${bytesRemaining} remaining bytes pushed to handleLengthBytes`);
this.handleLengthBytes(receivedBytes.slice(bytesToRead)); this.handleLengthBytes(receivedBytes.slice(bytesToRead));
} }
} }
@ -206,11 +206,8 @@ export class FCastSession {
} }
private handleNextPacket() { private handleNextPacket() {
logger.info(`Processing packet of ${this.bytesRead} bytes from`);
const opcode = this.buffer[0]; const opcode = this.buffer[0];
const body = this.packetLength > 1 ? this.buffer.toString('utf8', 1, this.packetLength) : null; const body = this.packetLength > 1 ? this.buffer.toString('utf8', 1, this.packetLength) : null;
logger.info('body', body);
this.handlePacket(opcode, body); this.handlePacket(opcode, body);
} }

View file

@ -0,0 +1,197 @@
export enum LoggerType {
BACKEND,
FRONTEND,
}
export class Logger {
private static log4js = null;
private static ipcLoggerTags = {
trace: [],
debug: [],
info: [],
warn: [],
error: [],
fatal: [],
};
private funcTable = {
trace: console.trace,
debug: console.debug,
info: console.log,
warn: console.warn,
error: console.error,
fatal: console.error,
};
public static initialize(config: any) {
// @ts-ignore
if (TARGET === 'electron') {
// @ts-ignore
const electronAPI = __non_webpack_require__('electron');
// @ts-ignore
Logger.log4js = __non_webpack_require__('log4js');
Logger.log4js.configure(config);
let logger = Logger.log4js.getLogger();
electronAPI.ipcMain.on('logger-trace', (event, value) => {
if (!Logger.ipcLoggerTags.trace.includes(value.tag)) {
Logger.ipcLoggerTags.trace.push(value.tag);
logger = Logger.log4js.getLogger(value.tag);
}
logger.info(value.message, ...value.optionalParams);
});
electronAPI.ipcMain.on('logger-debug', (event, value) => {
if (!Logger.ipcLoggerTags.debug.includes(value.tag)) {
Logger.ipcLoggerTags.debug.push(value.tag);
logger = Logger.log4js.getLogger(value.tag);
}
logger.info(value.message, ...value.optionalParams);
});
electronAPI.ipcMain.on('logger-info', (event, value) => {
if (!Logger.ipcLoggerTags.info.includes(value.tag)) {
Logger.ipcLoggerTags.info.push(value.tag);
logger = Logger.log4js.getLogger(value.tag);
}
logger.info(value.message, ...value.optionalParams);
});
electronAPI.ipcMain.on('logger-warn', (event, value) => {
if (!Logger.ipcLoggerTags.warn.includes(value.tag)) {
Logger.ipcLoggerTags.warn.push(value.tag);
logger = Logger.log4js.getLogger(value.tag);
}
logger.warn(value.message, ...value.optionalParams);
});
electronAPI.ipcMain.on('logger-error', (event, value) => {
if (!Logger.ipcLoggerTags.error.includes(value.tag)) {
Logger.ipcLoggerTags.error.push(value.tag);
logger = Logger.log4js.getLogger(value.tag);
}
logger.error(value.message, ...value.optionalParams);
});
electronAPI.ipcMain.on('logger-fatal', (event, value) => {
if (!Logger.ipcLoggerTags.fatal.includes(value.tag)) {
Logger.ipcLoggerTags.fatal.push(value.tag);
logger = Logger.log4js.getLogger(value.tag);
}
logger.fatal(value.message, ...value.optionalParams);
});
}
}
constructor(tag: string = 'default', type: LoggerType = LoggerType.FRONTEND) {
// @ts-ignore
if (TARGET === 'electron') {
if (type === LoggerType.BACKEND) {
// log4js should be initialized via the static method, but providing fallback when logger is used
// before initialization as done currently by the Store module on startup.
if (!Logger.log4js) {
// @ts-ignore
Logger.log4js = __non_webpack_require__('log4js');
}
const logger = Logger.log4js.getLogger(tag);
this.funcTable = {
trace: (message?: any, ...optionalParams: any[]) => {
logger.trace(message, ...optionalParams);
},
debug: (message?: any, ...optionalParams: any[]) => {
logger.debug(message, ...optionalParams);
},
info: (message?: any, ...optionalParams: any[]) => {
logger.info(message, ...optionalParams);
},
warn: (message?: any, ...optionalParams: any[]) => {
logger.warn(message, ...optionalParams);
},
error: (message?: any, ...optionalParams: any[]) => {
logger.error(message, ...optionalParams);
},
fatal: (message?: any, ...optionalParams: any[]) => {
logger.fatal(message, ...optionalParams);
},
};
}
else if (type === LoggerType.FRONTEND) {
// @ts-ignore
const electronAPI = __non_webpack_require__('electron');
this.funcTable = {
trace: (message?: any, ...optionalParams: any[]) => {
console.trace(message, ...optionalParams);
electronAPI.ipcRenderer.send('logger-trace', { tag: tag, message: message, optionalParams: optionalParams });
},
debug: (message?: any, ...optionalParams: any[]) => {
console.debug(message, ...optionalParams);
electronAPI.ipcRenderer.send('logger-debug', { tag: tag, message: message, optionalParams: optionalParams });
},
info: (message?: any, ...optionalParams: any[]) => {
console.log(message, ...optionalParams);
electronAPI.ipcRenderer.send('logger-info', { tag: tag, message: message, optionalParams: optionalParams });
},
warn: (message?: any, ...optionalParams: any[]) => {
console.warn(message, ...optionalParams);
electronAPI.ipcRenderer.send('logger-warn', { tag: tag, message: message, optionalParams: optionalParams });
},
error: (message?: any, ...optionalParams: any[]) => {
console.error(message, ...optionalParams);
electronAPI.ipcRenderer.send('logger-error', { tag: tag, message: message, optionalParams: optionalParams });
},
fatal: (message?: any, ...optionalParams: any[]) => {
console.error(message, ...optionalParams);
electronAPI.ipcRenderer.send('logger-fatal', { tag: tag, message: message, optionalParams: optionalParams });
},
};
}
// @ts-ignore
} else if (TARGET === 'webOS' || TARGET === 'tizenOS') {
} else {
// @ts-ignore
console.warn(`Attempting to initialize logger on unsupported target: ${TARGET}`);
}
}
public trace(message?: any, ...optionalParams: any[]): void {
this.funcTable.trace(message, ...optionalParams);
}
public debug(message?: any, ...optionalParams: any[]): void {
this.funcTable.debug(message, ...optionalParams);
}
public info(message?: any, ...optionalParams: any[]): void {
this.funcTable.info(message, ...optionalParams);
}
public warn(message?: any, ...optionalParams: any[]): void {
this.funcTable.warn(message, ...optionalParams);
}
public error(message?: any, ...optionalParams: any[]): void {
this.funcTable.error(message, ...optionalParams);
}
public fatal(message?: any, ...optionalParams: any[]): void {
this.funcTable.fatal(message, ...optionalParams);
}
public shutdown() {
// @ts-ignore
if (TARGET === 'electron') {
Logger.log4js.shutdown();
}
}
}

View file

@ -3,7 +3,8 @@ import * as http from 'http';
import * as url from 'url'; import * as url from 'url';
import { AddressInfo } from 'modules/ws'; import { AddressInfo } from 'modules/ws';
import { v4 as uuidv4 } from 'modules/uuid'; import { v4 as uuidv4 } from 'modules/uuid';
import { Main } from 'src/Main'; import { Logger, LoggerType } from 'common/Logger';
const logger = new Logger('NetworkService', LoggerType.BACKEND);
export class NetworkService { export class NetworkService {
static key: string = null; static key: string = null;
@ -15,11 +16,11 @@ export class NetworkService {
private static setupProxyServer(): Promise<void> { private static setupProxyServer(): Promise<void> {
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
try { try {
Main.logger.info(`Proxy server starting`); logger.info(`Proxy server starting`);
const port = 0; const port = 0;
NetworkService.proxyServer = http.createServer((req, res) => { NetworkService.proxyServer = http.createServer((req, res) => {
Main.logger.info(`Request received`); logger.info(`Request received`);
const requestUrl = `http://${req.headers.host}${req.url}`; const requestUrl = `http://${req.headers.host}${req.url}`;
const proxyInfo = NetworkService.proxiedFiles.get(requestUrl); const proxyInfo = NetworkService.proxiedFiles.get(requestUrl);
@ -60,7 +61,7 @@ export class NetworkService {
req.pipe(proxyReq, { end: true }); req.pipe(proxyReq, { end: true });
proxyReq.on('error', (e) => { proxyReq.on('error', (e) => {
Main.logger.error(`Problem with request: ${e.message}`); logger.error(`Problem with request: ${e.message}`);
res.writeHead(500); res.writeHead(500);
res.end(); res.end();
}); });
@ -70,7 +71,7 @@ export class NetworkService {
}); });
NetworkService.proxyServer.listen(port, '127.0.0.1', () => { NetworkService.proxyServer.listen(port, '127.0.0.1', () => {
NetworkService.proxyServerAddress = NetworkService.proxyServer.address() as AddressInfo; NetworkService.proxyServerAddress = NetworkService.proxyServer.address() as AddressInfo;
Main.logger.info(`Proxy server running at http://127.0.0.1:${NetworkService.proxyServerAddress.port}/`); logger.info(`Proxy server running at http://127.0.0.1:${NetworkService.proxyServerAddress.port}/`);
resolve(); resolve();
}); });
} catch (e) { } catch (e) {
@ -98,7 +99,7 @@ export class NetworkService {
} }
const proxiedUrl = `http://127.0.0.1:${NetworkService.proxyServerAddress.port}/${uuidv4()}`; const proxiedUrl = `http://127.0.0.1:${NetworkService.proxyServerAddress.port}/${uuidv4()}`;
Main.logger.info("Proxied url", { proxiedUrl, url, headers }); logger.info("Proxied url", { proxiedUrl, url, headers });
NetworkService.proxiedFiles.set(proxiedUrl, { url: url, headers: headers }); NetworkService.proxiedFiles.set(proxiedUrl, { url: url, headers: headers });
return proxiedUrl; return proxiedUrl;
} }

View file

@ -1,8 +1,10 @@
import * as net from 'net'; import * as net from 'net';
import { FCastSession } from 'common/FCastSession'; import { FCastSession } from 'common/FCastSession';
import { Opcode } from 'common/Packets'; import { Opcode } from 'common/Packets';
import { Logger, LoggerType } from 'common/Logger';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { Main, errorHandler } from 'src/Main'; import { errorHandler } from 'src/Main';
const logger = new Logger('TcpListenerService', LoggerType.BACKEND);
export class TcpListenerService { export class TcpListenerService {
public static PORT = 46899; public static PORT = 46899;
@ -35,12 +37,12 @@ export class TcpListenerService {
} }
send(opcode: number, message = null) { send(opcode: number, message = null) {
// Main.logger.info(`Sending message ${JSON.stringify(message)}`); // logger.info(`Sending message ${JSON.stringify(message)}`);
this.sessions.forEach(session => { this.sessions.forEach(session => {
try { try {
session.send(opcode, message); session.send(opcode, message);
} catch (e) { } catch (e) {
Main.logger.warn("Failed to send error.", e); logger.warn("Failed to send error.", e);
session.close(); session.close();
} }
}); });
@ -60,7 +62,7 @@ export class TcpListenerService {
} }
private handleConnection(socket: net.Socket) { private handleConnection(socket: net.Socket) {
Main.logger.info(`New connection from ${socket.remoteAddress}:${socket.remotePort}`); logger.info(`New connection from ${socket.remoteAddress}:${socket.remotePort}`);
const session = new FCastSession(socket, (data) => socket.write(data)); const session = new FCastSession(socket, (data) => socket.write(data));
session.bindEvents(this.emitter); session.bindEvents(this.emitter);
@ -68,7 +70,7 @@ export class TcpListenerService {
this.sessionMap.set(session.sessionId, session); this.sessionMap.set(session.sessionId, session);
socket.on("error", (err) => { socket.on("error", (err) => {
Main.logger.warn(`Error from ${socket.remoteAddress}:${socket.remotePort}.`, err); logger.warn(`Error from ${socket.remoteAddress}:${socket.remotePort}.`, err);
this.disconnect(session.sessionId); this.disconnect(session.sessionId);
}); });
@ -76,7 +78,7 @@ export class TcpListenerService {
try { try {
session.processBytes(buffer); session.processBytes(buffer);
} catch (e) { } catch (e) {
Main.logger.warn(`Error while handling packet from ${socket.remoteAddress}:${socket.remotePort}.`, e); logger.warn(`Error while handling packet from ${socket.remoteAddress}:${socket.remotePort}.`, e);
socket.end(); socket.end();
} }
}); });
@ -91,10 +93,10 @@ export class TcpListenerService {
this.emitter.emit('connect', { sessionId: session.sessionId, type: 'tcp', data: { address: socket.remoteAddress, port: socket.remotePort }}); this.emitter.emit('connect', { sessionId: session.sessionId, type: 'tcp', data: { address: socket.remoteAddress, port: socket.remotePort }});
try { try {
Main.logger.info('Sending version'); logger.info('Sending version');
session.send(Opcode.Version, {version: 2}); session.send(Opcode.Version, {version: 2});
} catch (e) { } catch (e) {
Main.logger.info('Failed to send version', e); logger.info('Failed to send version', e);
} }
} }
} }

View file

@ -1,8 +1,10 @@
import { FCastSession } from 'common/FCastSession'; import { FCastSession } from 'common/FCastSession';
import { Opcode } from 'common/Packets'; import { Opcode } from 'common/Packets';
import { Logger, LoggerType } from 'common/Logger';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { WebSocket, WebSocketServer } from 'modules/ws'; import { WebSocket, WebSocketServer } from 'modules/ws';
import { Main, errorHandler } from 'src/Main'; import { errorHandler } from 'src/Main';
const logger = new Logger('WebSocketListenerService', LoggerType.BACKEND);
export class WebSocketListenerService { export class WebSocketListenerService {
public static PORT = 46898; public static PORT = 46898;
@ -39,7 +41,7 @@ export class WebSocketListenerService {
try { try {
session.send(opcode, message); session.send(opcode, message);
} catch (e) { } catch (e) {
Main.logger.warn("Failed to send error.", e); logger.warn("Failed to send error.", e);
session.close(); session.close();
} }
}); });
@ -59,7 +61,7 @@ export class WebSocketListenerService {
} }
private handleConnection(socket: WebSocket) { private handleConnection(socket: WebSocket) {
Main.logger.info('New WebSocket connection'); logger.info('New WebSocket connection');
const session = new FCastSession(socket, (data) => socket.send(data)); const session = new FCastSession(socket, (data) => socket.send(data));
session.bindEvents(this.emitter); session.bindEvents(this.emitter);
@ -67,7 +69,7 @@ export class WebSocketListenerService {
this.sessionMap.set(session.sessionId, session); this.sessionMap.set(session.sessionId, session);
socket.on("error", (err) => { socket.on("error", (err) => {
Main.logger.warn(`Error.`, err); logger.warn(`Error.`, err);
this.disconnect(session.sessionId); this.disconnect(session.sessionId);
}); });
@ -76,16 +78,16 @@ export class WebSocketListenerService {
if (data instanceof Buffer) { if (data instanceof Buffer) {
session.processBytes(data); session.processBytes(data);
} else { } else {
Main.logger.warn("Received unhandled string message", data); logger.warn("Received unhandled string message", data);
} }
} catch (e) { } catch (e) {
Main.logger.warn(`Error while handling packet.`, e); logger.warn(`Error while handling packet.`, e);
session.close(); session.close();
} }
}); });
socket.on("close", () => { socket.on("close", () => {
Main.logger.info('WebSocket connection closed'); logger.info('WebSocket connection closed');
const index = this.sessions.indexOf(session); const index = this.sessions.indexOf(session);
if (index != -1) { if (index != -1) {
@ -96,10 +98,10 @@ export class WebSocketListenerService {
this.emitter.emit('connect', { sessionId: session.sessionId, type: 'ws', data: { url: socket.url }}); this.emitter.emit('connect', { sessionId: session.sessionId, type: 'ws', data: { url: socket.url }});
try { try {
Main.logger.info('Sending version'); logger.info('Sending version');
session.send(Opcode.Version, {version: 2}); session.send(Opcode.Version, {version: 2});
} catch (e) { } catch (e) {
Main.logger.info('Failed to send version'); logger.info('Failed to send version');
} }
} }
} }

View file

@ -1,6 +1,18 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */ /* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { Opcode } from 'common/Packets'; import { Opcode } from 'common/Packets';
import { Logger, LoggerType } from 'common/Logger';
const logger = new Logger('MainWindow', LoggerType.FRONTEND);
// Cannot directly pass the object to the renderer for some reason...
const loggerInterface = {
trace: (message?: any, ...optionalParams: any[]) => { logger.trace(message, ...optionalParams); },
debug: (message?: any, ...optionalParams: any[]) => { logger.debug(message, ...optionalParams); },
info: (message?: any, ...optionalParams: any[]) => { logger.info(message, ...optionalParams); },
warn: (message?: any, ...optionalParams: any[]) => { logger.warn(message, ...optionalParams); },
error: (message?: any, ...optionalParams: any[]) => { logger.error(message, ...optionalParams); },
fatal: (message?: any, ...optionalParams: any[]) => { logger.fatal(message, ...optionalParams); },
};
declare global { declare global {
interface Window { interface Window {
@ -32,15 +44,16 @@ if (TARGET === 'electron') {
onDisconnect: (callback: any) => electronAPI.ipcRenderer.on('disconnect', callback), onDisconnect: (callback: any) => electronAPI.ipcRenderer.on('disconnect', callback),
onPing: (callback: any) => electronAPI.ipcRenderer.on('ping', callback), onPing: (callback: any) => electronAPI.ipcRenderer.on('ping', callback),
onPong: (callback: any) => electronAPI.ipcRenderer.on('pong', callback), onPong: (callback: any) => electronAPI.ipcRenderer.on('pong', callback),
logger: loggerInterface,
}); });
// @ts-ignore // @ts-ignore
} else if (TARGET === 'webOS' || TARGET === 'tizenOS') { } else if (TARGET === 'webOS' || TARGET === 'tizenOS') {
preloadData = { preloadData = {
onDeviceInfoCb: () => { console.log('Main: Callback not set while fetching device info'); }, onDeviceInfoCb: () => { logger.error('Main: Callback not set while fetching device info'); },
onConnectCb: (_, value: any) => { console.log('Main: Callback not set while calling onConnect'); }, onConnectCb: (_, value: any) => { logger.error('Main: Callback not set while calling onConnect'); },
onDisconnectCb: (_, value: any) => { console.log('Main: Callback not set while calling onDisconnect'); }, onDisconnectCb: (_, value: any) => { logger.error('Main: Callback not set while calling onDisconnect'); },
onPingCb: (_, value: any) => { console.log('Main: Callback not set while calling onPing'); }, onPingCb: (_, value: any) => { logger.error('Main: Callback not set while calling onPing'); },
}; };
window.targetAPI = { window.targetAPI = {
@ -49,10 +62,11 @@ if (TARGET === 'electron') {
onDisconnect: (callback: (_, value: any) => void) => preloadData.onDisconnectCb = callback, onDisconnect: (callback: (_, value: any) => void) => preloadData.onDisconnectCb = callback,
onPing: (callback: (_, value: any) => void) => preloadData.onPingCb = callback, onPing: (callback: (_, value: any) => void) => preloadData.onPingCb = callback,
getDeviceInfo: () => preloadData.deviceInfo, getDeviceInfo: () => preloadData.deviceInfo,
logger: loggerInterface,
}; };
} else { } else {
// @ts-ignore // @ts-ignore
console.log(`Attempting to run FCast player on unsupported target: ${TARGET}`); logger.warn(`Attempting to run FCast player on unsupported target: ${TARGET}`);
} }
export { export {

View file

@ -12,6 +12,7 @@ let renderedAddresses = null;
let qrCodeUrl = null; let qrCodeUrl = null;
let qrWidth = null; let qrWidth = null;
const logger = window.targetAPI.logger;
window.addEventListener('resize', (event) => calculateQRCodeWidth()); window.addEventListener('resize', (event) => calculateQRCodeWidth());
connectionMonitor.setUiUpdateCallbacks({ connectionMonitor.setUiUpdateCallbacks({
@ -37,13 +38,13 @@ connectionMonitor.setUiUpdateCallbacks({
window.targetAPI.onDeviceInfo(renderIPsAndQRCode); window.targetAPI.onDeviceInfo(renderIPsAndQRCode);
if(window.targetAPI.getDeviceInfo()) { if(window.targetAPI.getDeviceInfo()) {
console.log('device info already present'); logger.info('device info already present');
renderIPsAndQRCode(); renderIPsAndQRCode();
} }
function renderIPsAndQRCode() { function renderIPsAndQRCode() {
const value = window.targetAPI.getDeviceInfo(); const value = window.targetAPI.getDeviceInfo();
console.log(`Network Interface Info: ${JSON.stringify(value)}`); logger.info(`Network Interface Info: ${JSON.stringify(value)}`);
renderIPs(value.interfaces); renderIPs(value.interfaces);
const addresses = []; const addresses = [];
@ -91,7 +92,7 @@ function renderIPsAndQRCode() {
let base64 = btoa(json); let base64 = btoa(json);
base64 = base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); base64 = base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
qrCodeUrl = `fcast://r/${base64}`; qrCodeUrl = `fcast://r/${base64}`;
console.log('QR Code:', {json, qrCodeUrl, base64}); logger.info('QR Code:', {json, qrCodeUrl, base64});
calculateQRCodeWidth(); calculateQRCodeWidth();
if (!renderedConnectionInfo) { if (!renderedConnectionInfo) {
@ -188,11 +189,11 @@ function renderQRCode(url: string) {
}, },
(err) => { (err) => {
if (err) { if (err) {
console.error(`Error rendering QR Code: ${err}`); logger.error(`Error rendering QR Code: ${err}`);
toast(`Error rendering QR Code: ${err}`, ToastIcon.ERROR); toast(`Error rendering QR Code: ${err}`, ToastIcon.ERROR);
} }
else { else {
console.log(`Rendered QR Code`); logger.info(`Rendered QR Code`);
} }
}); });

View file

@ -1,6 +1,8 @@
import dashjs from 'modules/dashjs'; import dashjs from 'modules/dashjs';
import Hls from 'modules/hls.js'; import Hls from 'modules/hls.js';
const logger = window.targetAPI.logger;
export enum PlayerType { export enum PlayerType {
Html, Html,
Dash, Dash,
@ -26,7 +28,7 @@ export class Player {
try { try {
(this.player as dashjs.MediaPlayerClass).destroy(); (this.player as dashjs.MediaPlayerClass).destroy();
} catch (e) { } catch (e) {
console.warn("Failed to destroy dash player", e); logger.warn("Failed to destroy dash player", e);
} }
this.player = null; this.player = null;
this.playerType = null; this.playerType = null;
@ -37,7 +39,7 @@ export class Player {
try { try {
this.hlsPlayer.destroy(); this.hlsPlayer.destroy();
} catch (e) { } catch (e) {
console.warn("Failed to destroy hls player", e); logger.warn("Failed to destroy hls player", e);
} }
// fall through // fall through
@ -65,7 +67,7 @@ export class Player {
} }
} }
play() { console.log("Player: play"); this.player.play(); } play() { logger.info("Player: play"); this.player.play(); }
isPaused(): boolean { isPaused(): boolean {
if (this.playerType === PlayerType.Dash) { if (this.playerType === PlayerType.Dash) {
@ -74,7 +76,7 @@ export class Player {
return (this.player as HTMLVideoElement).paused; return (this.player as HTMLVideoElement).paused;
} }
} }
pause() { console.log("Player: pause"); this.player.pause(); } pause() { logger.info("Player: pause"); this.player.pause(); }
getVolume(): number { getVolume(): number {
if (this.playerType === PlayerType.Dash) { if (this.playerType === PlayerType.Dash) {
@ -84,7 +86,7 @@ export class Player {
} }
} }
setVolume(value: number) { setVolume(value: number) {
console.log(`Player: setVolume ${value}`); logger.info(`Player: setVolume ${value}`);
const sanitizedVolume = Math.min(1.0, Math.max(0.0, value)); const sanitizedVolume = Math.min(1.0, Math.max(0.0, value));
if (this.playerType === PlayerType.Dash) { if (this.playerType === PlayerType.Dash) {
@ -102,7 +104,7 @@ export class Player {
} }
} }
setMute(value: boolean) { setMute(value: boolean) {
console.log(`Player: setMute ${value}`); logger.info(`Player: setMute ${value}`);
if (this.playerType === PlayerType.Dash) { if (this.playerType === PlayerType.Dash) {
(this.player as dashjs.MediaPlayerClass).setMute(value); (this.player as dashjs.MediaPlayerClass).setMute(value);
@ -119,7 +121,7 @@ export class Player {
} }
} }
setPlaybackRate(value: number) { setPlaybackRate(value: number) {
console.log(`Player: setPlaybackRate ${value}`); logger.info(`Player: setPlaybackRate ${value}`);
const sanitizedSpeed = Math.min(16.0, Math.max(0.0, value)); const sanitizedSpeed = Math.min(16.0, Math.max(0.0, value));
if (this.playerType === PlayerType.Dash) { if (this.playerType === PlayerType.Dash) {
@ -147,7 +149,7 @@ export class Player {
} }
} }
setCurrentTime(value: number) { setCurrentTime(value: number) {
// console.log(`Player: setCurrentTime ${value}`); // logger.info(`Player: setCurrentTime ${value}`);
const sanitizedTime = Math.min(this.getDuration(), Math.max(0.0, value)); const sanitizedTime = Math.min(this.getDuration(), Math.max(0.0, value));
if (this.playerType === PlayerType.Dash) { if (this.playerType === PlayerType.Dash) {

View file

@ -1,7 +1,18 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */ /* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { PlaybackErrorMessage, PlaybackUpdateMessage, VolumeUpdateMessage, Opcode } from 'common/Packets'; import { PlaybackErrorMessage, PlaybackUpdateMessage, VolumeUpdateMessage, Opcode } from 'common/Packets';
export {}; import { Logger, LoggerType } from 'common/Logger';
const logger = new Logger('PlayerWindow', LoggerType.FRONTEND);
// Cannot directly pass the object to the renderer for some reason...
const loggerInterface = {
trace: (message?: any, ...optionalParams: any[]) => { logger.trace(message, ...optionalParams); },
debug: (message?: any, ...optionalParams: any[]) => { logger.debug(message, ...optionalParams); },
info: (message?: any, ...optionalParams: any[]) => { logger.info(message, ...optionalParams); },
warn: (message?: any, ...optionalParams: any[]) => { logger.warn(message, ...optionalParams); },
error: (message?: any, ...optionalParams: any[]) => { logger.error(message, ...optionalParams); },
fatal: (message?: any, ...optionalParams: any[]) => { logger.fatal(message, ...optionalParams); },
};
declare global { declare global {
interface Window { interface Window {
@ -37,21 +48,22 @@ if (TARGET === 'electron') {
onDisconnect: (callback: any) => electronAPI.ipcRenderer.on('disconnect', callback), onDisconnect: (callback: any) => electronAPI.ipcRenderer.on('disconnect', callback),
onPing: (callback: any) => electronAPI.ipcRenderer.on('ping', callback), onPing: (callback: any) => electronAPI.ipcRenderer.on('ping', callback),
onPong: (callback: any) => electronAPI.ipcRenderer.on('pong', callback), onPong: (callback: any) => electronAPI.ipcRenderer.on('pong', callback),
logger: loggerInterface,
}); });
// @ts-ignore // @ts-ignore
} else if (TARGET === 'webOS' || TARGET === 'tizenOS') { } else if (TARGET === 'webOS' || TARGET === 'tizenOS') {
preloadData = { preloadData = {
sendPlaybackErrorCb: () => { console.error('Player: Callback "send_playback_error" not set'); }, sendPlaybackErrorCb: () => { logger.error('Player: Callback "send_playback_error" not set'); },
sendPlaybackUpdateCb: () => { console.error('Player: Callback "send_playback_update" not set'); }, sendPlaybackUpdateCb: () => { logger.error('Player: Callback "send_playback_update" not set'); },
sendVolumeUpdateCb: () => { console.error('Player: Callback "send_volume_update" not set'); }, sendVolumeUpdateCb: () => { logger.error('Player: Callback "send_volume_update" not set'); },
// onPlayCb: () => { console.error('Player: Callback "play" not set'); }, // onPlayCb: () => { logger.error('Player: Callback "play" not set'); },
onPlayCb: undefined, onPlayCb: undefined,
onPauseCb: () => { console.error('Player: Callback "pause" not set'); }, onPauseCb: () => { logger.error('Player: Callback "pause" not set'); },
onResumeCb: () => { console.error('Player: Callback "resume" not set'); }, onResumeCb: () => { logger.error('Player: Callback "resume" not set'); },
onSeekCb: () => { console.error('Player: Callback "onseek" not set'); }, onSeekCb: () => { logger.error('Player: Callback "onseek" not set'); },
onSetVolumeCb: () => { console.error('Player: Callback "setvolume" not set'); }, onSetVolumeCb: () => { logger.error('Player: Callback "setvolume" not set'); },
onSetSpeedCb: () => { console.error('Player: Callback "setspeed" not set'); }, onSetSpeedCb: () => { logger.error('Player: Callback "setspeed" not set'); },
}; };
window.targetAPI = { window.targetAPI = {
@ -64,10 +76,11 @@ if (TARGET === 'electron') {
onSeek: (callback: any) => { preloadData.onSeekCb = callback; }, onSeek: (callback: any) => { preloadData.onSeekCb = callback; },
onSetVolume: (callback: any) => { preloadData.onSetVolumeCb = callback; }, onSetVolume: (callback: any) => { preloadData.onSetVolumeCb = callback; },
onSetSpeed: (callback: any) => { preloadData.onSetSpeedCb = callback; }, onSetSpeed: (callback: any) => { preloadData.onSetSpeedCb = callback; },
logger: loggerInterface,
}; };
} else { } else {
// @ts-ignore // @ts-ignore
console.log(`Attempting to run FCast player on unsupported target: ${TARGET}`); logger.warn(`Attempting to run FCast player on unsupported target: ${TARGET}`);
} }
export { export {

View file

@ -12,6 +12,8 @@ import {
captionsLineHeight captionsLineHeight
} from 'src/player/Renderer'; } from 'src/player/Renderer';
const logger = window.targetAPI.logger;
function formatDuration(duration: number) { function formatDuration(duration: number) {
if (isNaN(duration)) { if (isNaN(duration)) {
return '00:00'; return '00:00';
@ -120,7 +122,7 @@ let captionsBaseHeight = 0;
let captionsContentHeight = 0; let captionsContentHeight = 0;
function onPlay(_event, value: PlayMessage) { function onPlay(_event, value: PlayMessage) {
console.log("Handle play message renderer", JSON.stringify(value)); logger.info("Handle play message renderer", JSON.stringify(value));
const currentVolume = player ? player.getVolume() : null; const currentVolume = player ? player.getVolume() : null;
const currentPlaybackRate = player ? player.getPlaybackRate() : null; const currentPlaybackRate = player ? player.getPlaybackRate() : null;
@ -143,7 +145,7 @@ function onPlay(_event, value: PlayMessage) {
if ((value.url || value.content) && value.container && videoElement) { if ((value.url || value.content) && value.container && videoElement) {
if (value.container === 'application/dash+xml') { if (value.container === 'application/dash+xml') {
console.log("Loading dash player"); logger.info("Loading dash player");
const dashPlayer = dashjs.MediaPlayer().create(); const dashPlayer = dashjs.MediaPlayer().create();
const source = value.content ? value.content : value.url; const source = value.content ? value.content : value.url;
player = new Player(PlayerType.Dash, dashPlayer, source); player = new Player(PlayerType.Dash, dashPlayer, source);
@ -236,7 +238,7 @@ function onPlay(_event, value: PlayMessage) {
} }
} else if ((value.container === 'application/vnd.apple.mpegurl' || value.container === 'application/x-mpegURL') && !videoElement.canPlayType(value.container)) { } else if ((value.container === 'application/vnd.apple.mpegurl' || value.container === 'application/x-mpegURL') && !videoElement.canPlayType(value.container)) {
console.log("Loading hls player"); logger.info("Loading hls player");
const config = { const config = {
xhrSetup: function (xhr: XMLHttpRequest) { xhrSetup: function (xhr: XMLHttpRequest) {
@ -277,7 +279,7 @@ function onPlay(_event, value: PlayMessage) {
// hlsPlayer.subtitleDisplay = true; // hlsPlayer.subtitleDisplay = true;
} else { } else {
console.log("Loading html player"); logger.info("Loading html player");
player = new Player(PlayerType.Html, videoElement, value.url); player = new Player(PlayerType.Html, videoElement, value.url);
videoElement.src = value.url; videoElement.src = value.url;
@ -307,7 +309,7 @@ function onPlay(_event, value: PlayMessage) {
}; };
videoElement.onerror = (event: Event | string, source?: string, lineno?: number, colno?: number, error?: Error) => { videoElement.onerror = (event: Event | string, source?: string, lineno?: number, colno?: number, error?: Error) => {
console.error("Player error", {source, lineno, colno, error}); logger.error("Player error", {source, lineno, colno, error});
}; };
videoElement.onloadedmetadata = (ev) => { videoElement.onloadedmetadata = (ev) => {
@ -419,7 +421,7 @@ function playerCtrlStateUpdate(event: PlayerControlEvent) {
break; break;
case PlayerControlEvent.VolumeChange: { case PlayerControlEvent.VolumeChange: {
// console.log(`VolumeChange: isMute ${player?.isMuted()}, volume: ${player?.getVolume()}`); // logger.info(`VolumeChange: isMute ${player?.isMuted()}, volume: ${player?.getVolume()}`);
const volume = Math.round(player?.getVolume() * playerCtrlVolumeBar.offsetWidth); const volume = Math.round(player?.getVolume() * playerCtrlVolumeBar.offsetWidth);
if (player?.isMuted()) { if (player?.isMuted()) {
@ -440,7 +442,7 @@ function playerCtrlStateUpdate(event: PlayerControlEvent) {
} }
case PlayerControlEvent.TimeUpdate: { case PlayerControlEvent.TimeUpdate: {
// console.log(`TimeUpdate: Position: ${player.getCurrentTime()}, Duration: ${player.getDuration()}`); // logger.info(`TimeUpdate: Position: ${player.getCurrentTime()}, Duration: ${player.getDuration()}`);
if (isLive) { if (isLive) {
if (isLivePosition && player.getDuration() - player.getCurrentTime() > livePositionWindow) { if (isLivePosition && player.getDuration() - player.getCurrentTime() > livePositionWindow) {
@ -736,7 +738,7 @@ const skipInterval = 10;
const volumeIncrement = 0.1; const volumeIncrement = 0.1;
function keyDownEventListener(event: any) { function keyDownEventListener(event: any) {
// console.log("KeyDown", event); // logger.info("KeyDown", event);
const handledCase = targetKeyDownEventListener(event); const handledCase = targetKeyDownEventListener(event);
if (handledCase) { if (handledCase) {
return; return;

View file

@ -4,14 +4,15 @@ import { DiscoveryService } from 'common/DiscoveryService';
import { TcpListenerService } from 'common/TcpListenerService'; import { TcpListenerService } from 'common/TcpListenerService';
import { WebSocketListenerService } from 'common/WebSocketListenerService'; import { WebSocketListenerService } from 'common/WebSocketListenerService';
import { NetworkService } from 'common/NetworkService'; import { NetworkService } from 'common/NetworkService';
import { Logger, LoggerType } from 'common/Logger';
import { Updater } from './Updater'; import { Updater } from './Updater';
import * as os from 'os'; import * as os from 'os';
import * as path from 'path'; import * as path from 'path';
import * as log4js from "log4js";
import yargs from 'yargs'; import yargs from 'yargs';
import { hideBin } from 'yargs/helpers'; import { hideBin } from 'yargs/helpers';
import { ToastIcon } from 'common/components/Toast'; import { ToastIcon } from 'common/components/Toast';
const cp = require('child_process'); const cp = require('child_process');
let logger = null;
export class Main { export class Main {
static shouldOpenMainWindow = true; static shouldOpenMainWindow = true;
@ -23,7 +24,6 @@ export class Main {
static webSocketListenerService: WebSocketListenerService; static webSocketListenerService: WebSocketListenerService;
static discoveryService: DiscoveryService; static discoveryService: DiscoveryService;
static tray: Tray; static tray: Tray;
static logger: log4js.Logger;
private static toggleMainWindow() { private static toggleMainWindow() {
if (Main.mainWindow) { if (Main.mainWindow) {
@ -68,7 +68,7 @@ export class Main {
}); });
} }
Main.logger.error('Failed to check for updates:', err); logger.error('Failed to check for updates:', err);
} }
} }
@ -180,8 +180,8 @@ export class Main {
l.emitter.on("resume", () => Main.playerWindow?.webContents?.send("resume")); l.emitter.on("resume", () => Main.playerWindow?.webContents?.send("resume"));
l.emitter.on("stop", () => { l.emitter.on("stop", () => {
Main.playerWindow?.close(); Main.playerWindow?.close();
Main.playerWindow = null; Main.playerWindow = null;
}); });
l.emitter.on("seek", (message) => Main.playerWindow?.webContents?.send("seek", message)); l.emitter.on("seek", (message) => Main.playerWindow?.webContents?.send("seek", message));
@ -242,7 +242,7 @@ export class Main {
defaultId: 0 defaultId: 0
}); });
Main.logger.error('Failed to download update:', err); logger.error('Failed to download update:', err);
Main.mainWindow?.webContents?.send("download-failed"); Main.mainWindow?.webContents?.send("download-failed");
} }
} }
@ -342,7 +342,7 @@ export class Main {
Main.mainWindow.on('closed', () => { Main.mainWindow.on('closed', () => {
Main.mainWindow = null; Main.mainWindow = null;
if (!networkWorker.isDestoryed()) { if (!networkWorker.isDestroyed()) {
networkWorker.close(); networkWorker.close();
} }
}); });
@ -366,27 +366,28 @@ export class Main {
}) })
.options({ .options({
'no-main-window': { type: 'boolean', default: false, desc: "Start minimized to tray" }, 'no-main-window': { type: 'boolean', default: false, desc: "Start minimized to tray" },
'fullscreen': { type: 'boolean', default: false, desc: "Start application in fullscreen" } 'fullscreen': { type: 'boolean', default: false, desc: "Start application in fullscreen" },
'log': { chocies: ['ALL', 'TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL', 'MARK', 'OFF'], alias: 'loglevel', default: 'INFO', desc: "Defines the verbosity level of the logger" },
}) })
.parseSync(); .parseSync();
const isUpdating = Updater.isUpdating(); const isUpdating = Updater.isUpdating();
const fileLogType = isUpdating ? 'fileSync' : 'file'; const fileLogType = isUpdating ? 'fileSync' : 'file';
log4js.configure({ Logger.initialize({
appenders: { appenders: {
out: { type: 'stdout' }, out: { type: 'stdout' },
log: { type: fileLogType, filename: path.join(app.getPath('logs'), 'fcast-receiver.log'), flags: 'a', maxLogSize: '5M' }, log: { type: fileLogType, filename: path.join(app.getPath('logs'), 'fcast-receiver.log'), flags: 'a', maxLogSize: '5M' },
}, },
categories: { categories: {
default: { appenders: ['out', 'log'], level: 'info' }, default: { appenders: ['out', 'log'], level: argv.log },
}, },
}); });
Main.logger = log4js.getLogger(); logger = new Logger('Main', LoggerType.BACKEND);
Main.logger.info(`Starting application: ${app.name} | ${app.getAppPath()}`); logger.info(`Starting application: ${app.name} | ${app.getAppPath()}`);
Main.logger.info(`Version: ${app.getVersion()}`); logger.info(`Version: ${app.getVersion()}`);
Main.logger.info(`Commit: ${Updater.getCommit()}`); logger.info(`Commit: ${Updater.getCommit()}`);
Main.logger.info(`Release channel: ${Updater.releaseChannel} - ${Updater.getChannelVersion()}`); logger.info(`Release channel: ${Updater.releaseChannel} - ${Updater.getChannelVersion()}`);
Main.logger.info(`OS: ${process.platform} ${process.arch}`); logger.info(`OS: ${process.platform} ${process.arch}`);
if (isUpdating) { if (isUpdating) {
await Updater.processUpdate(); await Updater.processUpdate();
@ -415,7 +416,7 @@ export class Main {
Main.application.on('window-all-closed', () => { }); Main.application.on('window-all-closed', () => { });
} }
catch (err) { catch (err) {
Main.logger.error(`Error starting application: ${err}`); logger.error(`Error starting application: ${err}`);
app.exit(); app.exit();
} }
} }
@ -435,15 +436,15 @@ export function getComputerName() {
hostname = os.hostname(); hostname = os.hostname();
} }
catch (err) { catch (err) {
Main.logger.warn('Error fetching hostname, trying different method...'); logger.warn('Error fetching hostname, trying different method...');
Main.logger.warn(err); logger.warn(err);
try { try {
hostname = cp.execSync("hostnamectl hostname").toString().trim(); hostname = cp.execSync("hostnamectl hostname").toString().trim();
} }
catch (err2) { catch (err2) {
Main.logger.warn('Error fetching hostname again, using generic name...'); logger.warn('Error fetching hostname again, using generic name...');
Main.logger.warn(err2); logger.warn(err2);
hostname = 'linux device'; hostname = 'linux device';
} }
@ -458,7 +459,7 @@ export function getComputerName() {
} }
export async function errorHandler(err: NodeJS.ErrnoException) { export async function errorHandler(err: NodeJS.ErrnoException) {
Main.logger.error("Application error:", err); logger.error("Application error:", err);
Main.mainWindow?.webContents?.send("toast", { message: err, icon: ToastIcon.ERROR }); Main.mainWindow?.webContents?.send("toast", { message: err, icon: ToastIcon.ERROR });
const restartPrompt = await dialog.showMessageBox({ const restartPrompt = await dialog.showMessageBox({

View file

@ -1,8 +1,8 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import storage from 'electron-json-storage'; import storage from 'electron-json-storage';
import { app } from 'electron'; import { app } from 'electron';
import * as log4js from "log4js"; import { Logger, LoggerType } from 'common/Logger';
const logger = log4js.getLogger(); const logger = new Logger('Store', LoggerType.BACKEND);
export class Store { export class Store {
private static storeVersion = 1; private static storeVersion = 1;

View file

@ -2,13 +2,14 @@ import * as fs from 'fs';
import * as https from 'https'; import * as https from 'https';
import * as path from 'path'; import * as path from 'path';
import * as crypto from 'crypto'; import * as crypto from 'crypto';
import * as log4js from "log4js";
import { app } from 'electron'; import { app } from 'electron';
import { Store } from './Store'; import { Store } from './Store';
import sudo from 'sudo-prompt'; import sudo from 'sudo-prompt';
import { Logger, LoggerType } from 'common/Logger';
const cp = require('child_process'); const cp = require('child_process');
const extract = require('extract-zip'); const extract = require('extract-zip');
const logger = log4js.getLogger(); const logger = new Logger('Updater', LoggerType.BACKEND);
enum UpdateState { enum UpdateState {
Copy = 'copy', Copy = 'copy',
@ -193,7 +194,7 @@ export class Updater {
// Also does not work very well on Mac... // Also does not work very well on Mac...
private static relaunch(binPath: string) { private static relaunch(binPath: string) {
logger.info(`Relaunching app binary: ${binPath}`); logger.info(`Relaunching app binary: ${binPath}`);
log4js.shutdown(); logger.shutdown();
let proc; let proc;
if (process.platform === 'win32') { if (process.platform === 'win32') {
@ -394,7 +395,8 @@ export class Updater {
logger.info('Extraction complete.'); logger.info('Extraction complete.');
const updateInfo: UpdateInfo = { const updateInfo: UpdateInfo = {
updateState: UpdateState.Copy, // updateState: UpdateState.Copy,
updateState: UpdateState.Cleanup,
installPath: Updater.installPath, installPath: Updater.installPath,
tempPath: path.dirname(destination), tempPath: path.dirname(destination),
currentVersion: Updater.releasesJson.currentVersion, currentVersion: Updater.releasesJson.currentVersion,

View file

@ -1,5 +1,7 @@
import { ipcRenderer } from 'electron'; import { ipcRenderer } from 'electron';
import si from 'modules/systeminformation'; import si from 'modules/systeminformation';
import { Logger, LoggerType } from 'common/Logger';
const logger = new Logger('NetworkWorker', LoggerType.FRONTEND);
const networkStateChangeListenerTimeout = 2500; const networkStateChangeListenerTimeout = 2500;
let networkStateChangeListenerInterfaces = []; let networkStateChangeListenerInterfaces = [];
@ -10,11 +12,11 @@ setInterval(networkStateChangeListener, networkStateChangeListenerTimeout);
function networkStateChangeListener(forceUpdate: boolean) { function networkStateChangeListener(forceUpdate: boolean) {
new Promise<void>((resolve) => { new Promise<void>((resolve) => {
si.networkInterfaces((data) => { si.networkInterfaces((data) => {
// console.log(data); // logger.info(data);
const queriedInterfaces = Array.isArray(data) ? data : [data]; const queriedInterfaces = Array.isArray(data) ? data : [data];
si.wifiConnections((data) => { si.wifiConnections((data) => {
// console.log(data); // logger.info(data);
const wifiConnections = Array.isArray(data) ? data : [data]; const wifiConnections = Array.isArray(data) ? data : [data];
const interfaces = []; const interfaces = [];

View file

@ -1,5 +1,6 @@
import 'common/main/Renderer'; import 'common/main/Renderer';
const logger = window.targetAPI.logger;
export function onQRCodeRendered() {} export function onQRCodeRendered() {}
const updateView = document.getElementById("update-view"); const updateView = document.getElementById("update-view");
@ -14,7 +15,7 @@ const progressBarProgress = document.getElementById("progress-bar-progress");
let updaterProgressUIUpdateTimer = null; let updaterProgressUIUpdateTimer = null;
window.electronAPI.onUpdateAvailable(() => { window.electronAPI.onUpdateAvailable(() => {
console.log(`Received UpdateAvailable event`); logger.info(`Received UpdateAvailable event`);
updateViewTitle.textContent = 'FCast update available'; updateViewTitle.textContent = 'FCast update available';
updateText.textContent = 'Do you wish to update now?'; updateText.textContent = 'Do you wish to update now?';
@ -26,7 +27,7 @@ window.electronAPI.onUpdateAvailable(() => {
}); });
window.electronAPI.onDownloadComplete(() => { window.electronAPI.onDownloadComplete(() => {
console.log(`Received DownloadComplete event`); logger.info(`Received DownloadComplete event`);
window.clearTimeout(updaterProgressUIUpdateTimer); window.clearTimeout(updaterProgressUIUpdateTimer);
updateViewTitle.textContent = 'FCast update ready'; updateViewTitle.textContent = 'FCast update ready';
@ -39,7 +40,7 @@ window.electronAPI.onDownloadComplete(() => {
}); });
window.electronAPI.onDownloadFailed(() => { window.electronAPI.onDownloadFailed(() => {
console.log(`Received DownloadFailed event`); logger.info(`Received DownloadFailed event`);
window.clearTimeout(updaterProgressUIUpdateTimer); window.clearTimeout(updaterProgressUIUpdateTimer);
updateView.setAttribute("style", "display: none"); updateView.setAttribute("style", "display: none");
}); });