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

Moved network interface querying off main process

This commit is contained in:
Michael Hollister 2025-04-23 19:21:17 -05:00
parent 28a617daa7
commit 7ce2dcbca3
8 changed files with 143 additions and 123 deletions

View file

@ -1,11 +1,9 @@
import { PlayMessage, PlaybackErrorMessage, PlaybackUpdateMessage, VolumeUpdateMessage } from 'common/Packets';
import * as os from 'os';
import * as http from 'http';
import * as url from 'url';
import { AddressInfo } from 'modules/ws';
import { v4 as uuidv4 } from 'modules/uuid';
import { Main } from 'src/Main';
import si from 'modules/systeminformation';
export class NetworkService {
static key: string = null;
@ -13,8 +11,6 @@ export class NetworkService {
static proxyServer: http.Server;
static proxyServerAddress: AddressInfo;
static proxiedFiles: Map<string, { url: string, headers: { [key: string]: string } }> = new Map();
static networkStateChangeListenerTimeout = 2500;
private static networkStateChangeListenerInterfaces = [];
private static setupProxyServer(): Promise<void> {
return new Promise<void>((resolve, reject) => {
@ -106,55 +102,4 @@ export class NetworkService {
NetworkService.proxiedFiles.set(proxiedUrl, { url: url, headers: headers });
return proxiedUrl;
}
static async networkStateChangeListener(forceUpdate: boolean, networkChangedCb: (networkInfo: any) => void) {
const queriedInterfaces: si.Systeminformation.NetworkInterfacesData[] = await new Promise<si.Systeminformation.NetworkInterfacesData[]>((resolve, reject) => {
si.networkInterfaces((data) => {
// console.log(data);
if (Array.isArray(data)) {
resolve(data);
}
else {
resolve([data]);
}
});
});
const wifiConnections: si.Systeminformation.WifiConnectionData[] = await new Promise<si.Systeminformation.WifiConnectionData[]>((resolve, reject) => {
si.wifiConnections((data) => {
// console.log(data);
if (Array.isArray(data)) {
resolve(data);
}
else {
resolve([data]);
}
});
});
const interfaces = [];
for (const iface of queriedInterfaces) {
if (iface.ip4 !== '' && !iface.internal && !iface.virtual) {
const isWireless = wifiConnections.some(e => {
if (e.iface === iface.iface) {
interfaces.push({ type: 'wireless', name: e.ssid, address: iface.ip4, signalLevel: e.quality });
return true;
}
return false;
});
if (!isWireless) {
interfaces.push({ type: 'wired', name: iface.ifaceName, address: iface.ip4 });
}
}
}
if (forceUpdate || (JSON.stringify(interfaces) !== JSON.stringify(NetworkService.networkStateChangeListenerInterfaces))) {
NetworkService.networkStateChangeListenerInterfaces = interfaces;
networkChangedCb(interfaces);
}
}
}

View file

@ -7,6 +7,7 @@ const connectionStatusText = document.getElementById("connection-status-text");
const connectionStatusSpinner = document.getElementById("connection-spinner");
const connectionStatusCheck = document.getElementById("connection-check");
let connections = [];
let renderedConnectionInfo = false;
let renderedAddresses = null;
// Window might be re-created while devices are still connected
@ -66,8 +67,8 @@ function renderIPsAndQRCode() {
toast("Network connections has changed, please reconnect sender devices to receiver if you experience issues", ToastIcon.WARNING);
}
else if (addresses.length === 0) {
connInfo.setAttribute("style", "display: none");
connError.setAttribute("style", "display: block");
connInfo.style.display = 'none';
connError.style.display = 'block';
if (renderedAddresses !== null) {
toast("Lost network connection, please reconnect to a network", ToastIcon.ERROR);
@ -78,8 +79,8 @@ function renderIPsAndQRCode() {
}
if (renderedAddresses !== null && renderedAddresses.length === 0) {
connInfo.setAttribute("style", "display: block");
connError.setAttribute("style", "display: none");
connInfo.style.display = 'block';
connError.style.display = 'none';
}
renderIPs(value.interfaces);
@ -124,6 +125,12 @@ function renderIPsAndQRCode() {
}
});
if (!renderedConnectionInfo) {
const connInfoLoading = document.getElementById('connection-information-loading');
connInfoLoading.style.display = 'none';
connInfo.style.display = 'block';
}
onQRCodeRendered();
}

View file

@ -72,11 +72,15 @@ body, html {
gap: 15vw;
font-family: InterVariable;
font-size: 20px;
font-size: 28px;
font-style: normal;
font-weight: 400;
}
#main-view {
padding: 25px;
}
#title-container {
display: flex;
justify-content: center;
@ -85,7 +89,7 @@ body, html {
#title-text {
font-family: Outfit;
font-size: 100px;
font-size: 140px;
font-weight: 800;
text-align: center;
@ -96,12 +100,12 @@ body, html {
}
#title-icon {
width: 84px;
height: 84px;
width: 124px;
height: 124px;
background-image: url(../assets/icons/app/icon.svg);
background-size: cover;
margin-right: 15px;
margin-right: 25px;
}
#connection-status {
@ -109,35 +113,13 @@ body, html {
text-align: center;
}
#main-view {
padding: 25px;
}
#manual-connection-info {
font-weight: 700;
line-height: 24px;
margin: 10px;
}
#manual-connection-info-separator {
height: 1px;
background: #2E2E2E;
margin-top: 3px;
margin-bottom: 3px;
}
#qr-code {
display: flex;
margin: 20px auto;
flex-direction: column;
align-items: center;
padding: 20px;
background-color: white;
}
#scan-to-connect {
#connection-status-text {
margin-top: 20px;
font-weight: bold;
white-space: pre;
}
#connection-spinner {
padding: 20px;
}
#connection-error {
@ -159,9 +141,37 @@ body, html {
font-weight: bold;
}
#connection-status-text {
#connection-information-loading {
display: flex;
flex-direction: column;
align-items: center;
}
#connection-information-loading-text {
width: auto;
height: auto;
margin: 10px 20px;
}
#connection-information {
display: none;
flex-direction: column;
align-items: center;
justify-content: center;
}
#scan-to-connect {
margin-top: 20px;
white-space: pre;
font-weight: bold;
}
#qr-code {
display: flex;
margin: 20px auto;
flex-direction: column;
align-items: center;
padding: 20px;
background-color: white;
}
#ips {
@ -219,10 +229,6 @@ body, html {
background-image: url(../assets/icons/app/wifi-strength-outline.svg);
}
#connection-spinner {
padding: 20px;
}
#window-can-be-closed {
color: #666666;
position: absolute;
@ -230,7 +236,7 @@ body, html {
margin-bottom: 20px;
font-family: InterVariable;
font-size: 18px;
font-size: 24px;
font-style: normal;
font-weight: 400;
}
@ -238,15 +244,15 @@ body, html {
.lds-ring {
display: inline-block;
position: relative;
width: 80px;
height: 80px;
width: 120px;
height: 120px;
}
.lds-ring div {
box-sizing: border-box;
display: block;
position: absolute;
width: 64px;
height: 64px;
width: 104px;
height: 104px;
margin: 8px;
border: 8px solid #fff;
border-radius: 50%;
@ -275,8 +281,8 @@ body, html {
/* display: inline-block; */
display: none;
position: relative;
width: 64px;
height: 64px;
width: 104px;
height: 104px;
margin: 18px;
padding: 10px;
@ -329,8 +335,8 @@ body, html {
}
#toast-icon {
width: 48px;
height: 48px;
width: 88px;
height: 88px;
background-image: url(../assets/icons/app/info.svg);
background-size: cover;
flex-shrink: 0;
@ -345,7 +351,7 @@ body, html {
word-break: break-word;
font-family: InterVariable;
font-size: 20px;
font-size: 28px;
font-style: normal;
font-weight: 400;
}

View file

@ -302,27 +302,28 @@ export class Main {
}
});
let networkStateChangeListener = null;
Main.mainWindow.loadFile(path.join(__dirname, 'main/index.html'));
Main.mainWindow.on('closed', () => {
Main.mainWindow = null;
clearInterval(networkStateChangeListener);
});
Main.mainWindow.maximize();
Main.mainWindow.show();
Main.mainWindow.on('ready-to-show', () => {
NetworkService.networkStateChangeListener(true, (interfaces: any) => {
Main.mainWindow.webContents.send("device-info", { name: os.hostname(), interfaces: interfaces });
networkStateChangeListener = setInterval(() => {
NetworkService.networkStateChangeListener(false, (interfaces: any) => {
Main.mainWindow.webContents.send("device-info", { name: os.hostname(), interfaces: interfaces });
});
},
NetworkService.networkStateChangeListenerTimeout);
const networkWorker = new BrowserWindow({
show: false,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
preload: path.join(__dirname, 'main/networkWorker.js')
}
});
ipcMain.on('network-changed', (event: IpcMainEvent, value: any) => {
Main.mainWindow.webContents.send("device-info", { name: os.hostname(), interfaces: value });
});
networkWorker.loadFile(path.join(__dirname, 'main/worker.html'));
});
}

View file

@ -0,0 +1,47 @@
import { ipcRenderer } from 'electron';
import si from 'modules/systeminformation';
const networkStateChangeListenerTimeout = 2500;
let networkStateChangeListenerInterfaces = [];
networkStateChangeListener(true);
setInterval(networkStateChangeListener, networkStateChangeListenerTimeout);
function networkStateChangeListener(forceUpdate: boolean) {
new Promise<void>((resolve) => {
si.networkInterfaces((data) => {
// console.log(data);
const queriedInterfaces = Array.isArray(data) ? data : [data];
si.wifiConnections((data) => {
// console.log(data);
const wifiConnections = Array.isArray(data) ? data : [data];
const interfaces = [];
for (const iface of queriedInterfaces) {
if (iface.ip4 !== '' && !iface.internal && !iface.virtual) {
const isWireless = wifiConnections.some(e => {
if (e.iface === iface.iface) {
interfaces.push({ type: 'wireless', name: e.ssid, address: iface.ip4, signalLevel: e.quality });
return true;
}
return false;
});
if (!isWireless) {
interfaces.push({ type: 'wired', name: iface.ifaceName, address: iface.ip4 });
}
}
}
if (forceUpdate || (JSON.stringify(interfaces) !== JSON.stringify(networkStateChangeListenerInterfaces))) {
networkStateChangeListenerInterfaces = interfaces;
ipcRenderer.send('network-changed', interfaces);
}
resolve();
});
});
});
}

View file

@ -47,6 +47,14 @@
<div class="non-selectable card-title">Connection Information</div>
<div class="card-title-separator"></div>
<div id="connection-information-loading">
<div id="connection-information-loading-text" class="lds-ring">Fetching Network Info...</div>
<div id="connection-information-loading-spinner" class="lds-ring"><div></div><div></div><div></div><div></div></div>
</div>
<div id="connection-error">
<div id="connection-error-icon"></div>
<div id="connection-error-text">Device not connected to a network</div>
</div>
<div id="connection-information">
<div id="scan-to-connect" class="non-selectable">Scan with a FCast sender app</div>
<canvas id="qr-code"></canvas>
@ -64,10 +72,6 @@
<div id="ip-ports">Port<br>46899 (TCP), 46898 (WS)</div>
</div>
</div>
<div id="connection-error">
<div id="connection-error-icon"></div>
<div id="connection-error-text">Device not connected to a network</div>
</div>
</div>
</div>

View file

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>FCast Receiver Worker</title>
<meta charset="UTF-8">
</head>
<body>
</body>
</html>

View file

@ -63,6 +63,7 @@ module.exports = [
entry: {
preload: './src/main/Preload.ts',
renderer: './src/main/Renderer.ts',
networkWorker: './src/main/NetworkWorker.ts'
},
target: 'electron-renderer',
module: {