mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
Merge pull request #673 from DJ2LS/dev-nsis-installer
NSIS Installer for Windows
This commit is contained in:
commit
9520bb4689
26 changed files with 413 additions and 675 deletions
|
@ -14,6 +14,15 @@ jobs:
|
|||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Electron Builder
|
||||
working-directory: gui
|
||||
run: |
|
||||
npm i
|
||||
npm run build
|
||||
|
||||
- name: LIST ALL FILES
|
||||
run: ls -R
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
|
@ -36,9 +45,9 @@ jobs:
|
|||
run: ls -R
|
||||
|
||||
- name: Create installer
|
||||
uses: joncloud/makensis-action@v4
|
||||
uses: joncloud/makensis-action@v4.1
|
||||
with:
|
||||
script-file: "freedata-server-nsis-config.nsi"
|
||||
script-file: "freedata-nsis-config.nsi"
|
||||
arguments: '/V3'
|
||||
|
||||
- name: LIST ALL FILES
|
||||
|
@ -47,12 +56,14 @@ jobs:
|
|||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: 'FreeData-Server-Installer'
|
||||
path: ./FreeData-Server-Installer.exe
|
||||
name: 'FreeDATA-Installer'
|
||||
path: ./FreeDATA-Installer.exe
|
||||
|
||||
- name: Upload Installer to Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
with:
|
||||
draft: true
|
||||
files: ./FreeData-Server-Installer.exe
|
||||
files: ./FreeDATA-Installer.exe
|
||||
tag_name: ${{ github.ref_name }}
|
||||
name: 'FreeDATA-Installer-${{ github.ref_name }}'
|
2
.github/workflows/build_server.yml
vendored
2
.github/workflows/build_server.yml
vendored
|
@ -48,7 +48,7 @@ jobs:
|
|||
brew install portaudio
|
||||
python -m pip install --upgrade pip
|
||||
pip3 install pyaudio
|
||||
export PYTHONPATH=/opt/homebrew/opt/portaudio/lib/:$PYTHONPATH
|
||||
export PYTHONPATH=/usr/local/lib/:$PYTHONPATH
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
|
|
132
freedata-nsis-config.nsi
Normal file
132
freedata-nsis-config.nsi
Normal file
|
@ -0,0 +1,132 @@
|
|||
!include "MUI2.nsh"
|
||||
|
||||
; Request administrative rights
|
||||
RequestExecutionLevel admin
|
||||
|
||||
; The name and file name of the installer
|
||||
Name "FreeDATA Installer"
|
||||
OutFile "FreeDATA-Installer.exe"
|
||||
|
||||
; Default installation directory for the server
|
||||
InstallDir "$LOCALAPPDATA\FreeDATA"
|
||||
|
||||
; Registry key to store the installation directory
|
||||
InstallDirRegKey HKCU "Software\FreeDATA" "Install_Dir"
|
||||
|
||||
; Modern UI settings
|
||||
!define MUI_ABORTWARNING
|
||||
|
||||
; Installer interface settings
|
||||
!define MUI_ICON "documentation\icon.ico"
|
||||
!define MUI_UNICON "documentation\icon.ico" ; Icon for the uninstaller
|
||||
|
||||
; Define the welcome page text
|
||||
!define MUI_WELCOMEPAGE_TEXT "Welcome to the FreeDATA Setup Wizard. This wizard will guide you through the installation process."
|
||||
!define MUI_FINISHPAGE_TEXT "Folder: $INSTDIR"
|
||||
!define MUI_DIRECTORYPAGE_TEXT_TOP "Please select the installation folder. It's recommended to use the suggested one to avoid permission problems."
|
||||
|
||||
; Pages
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
!insertmacro MUI_PAGE_LICENSE "LICENSE"
|
||||
!insertmacro MUI_PAGE_COMPONENTS
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
; Uninstaller
|
||||
!insertmacro MUI_UNPAGE_WELCOME
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
!insertmacro MUI_UNPAGE_FINISH
|
||||
|
||||
; Language (you can choose and configure the language(s) you want)
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
|
||||
|
||||
; Installer Sections
|
||||
Section "FreeData Server" SEC01
|
||||
; Set output path to the installation directory
|
||||
SetOutPath $INSTDIR\freedata-server
|
||||
|
||||
; Check if "config.ini" exists and back it up
|
||||
IfFileExists $INSTDIR\freedata-server\config.ini backupConfig
|
||||
|
||||
doneBackup:
|
||||
; Add your application files here
|
||||
File /r "modem\server.dist\*"
|
||||
|
||||
; Restore the original "config.ini" if it was backed up
|
||||
IfFileExists $INSTDIR\freedata-server\config.ini.bak restoreConfig
|
||||
|
||||
; Create a shortcut in the user's desktop
|
||||
CreateShortCut "$DESKTOP\FreeDATA Server.lnk" "$INSTDIR\freedata-server\freedata-server.exe"
|
||||
|
||||
; Create Uninstaller
|
||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||
|
||||
; Create a Start Menu directory
|
||||
CreateDirectory "$SMPROGRAMS\FreeDATA"
|
||||
|
||||
; Create shortcut in the Start Menu directory
|
||||
CreateShortCut "$SMPROGRAMS\FreeDATA\FreeDATA Server.lnk" "$INSTDIR\freedata-server\freedata-server.exe"
|
||||
|
||||
; Create an Uninstall shortcut
|
||||
CreateShortCut "$SMPROGRAMS\FreeDATA\Uninstall FreeDATA.lnk" "$INSTDIR\Uninstall.exe"
|
||||
|
||||
|
||||
; Backup "config.ini" before overwriting files
|
||||
backupConfig:
|
||||
Rename $INSTDIR\freedata-server\config.ini $INSTDIR\freedata-server\config.ini.bak
|
||||
Goto doneBackup
|
||||
|
||||
; Restore the original "config.ini"
|
||||
restoreConfig:
|
||||
Delete $INSTDIR\freedata-server\config.ini
|
||||
Rename $INSTDIR\freedata-server\config.ini.bak $INSTDIR\freedata-server\config.ini
|
||||
|
||||
|
||||
|
||||
SectionEnd
|
||||
|
||||
Section "FreeData x64 GUI" SEC02
|
||||
; Set output path to the GUI installation directory
|
||||
SetOutPath $INSTDIR\freedata-gui
|
||||
|
||||
; Add GUI files here
|
||||
File /r "gui\release\win-unpacked\*"
|
||||
|
||||
; Create a shortcut on the desktop for the GUI
|
||||
CreateShortCut "$DESKTOP\FreeDATA GUI.lnk" "$INSTDIR\freedata-gui\freedata.exe"
|
||||
|
||||
; Create a start menu shortcut
|
||||
CreateShortCut "$SMPROGRAMS\FreeDATA\FreeDATA GUI.lnk" "$INSTDIR\freedata-gui\freedata.exe"
|
||||
|
||||
; Create an Uninstall shortcut
|
||||
CreateShortCut "$SMPROGRAMS\FreeDATA\Uninstall FreeDATA.lnk" "$INSTDIR\Uninstall.exe"
|
||||
|
||||
SectionEnd
|
||||
|
||||
; Uninstaller Section
|
||||
Section "Uninstall"
|
||||
; Delete files and directories for the server
|
||||
Delete $INSTDIR\freedata-server\*.*
|
||||
RMDir /r $INSTDIR\freedata-server
|
||||
|
||||
; Delete files and directories for the GUI
|
||||
Delete $INSTDIR\freedata-gui\*.*
|
||||
RMDir /r $INSTDIR\freedata-gui
|
||||
|
||||
; Remove the desktop shortcuts
|
||||
Delete "$DESKTOP\FreeDATA Server.lnk"
|
||||
Delete "$DESKTOP\FreeDATA GUI.lnk"
|
||||
|
||||
; Remove Start Menu shortcuts
|
||||
Delete "$SMPROGRAMS\FreeDATA\*.*"
|
||||
RMDir "$SMPROGRAMS\FreeDATA"
|
||||
|
||||
; Attempt to delete the uninstaller itself
|
||||
Delete $EXEPATH
|
||||
|
||||
; Now remove the installation directory if it's empty
|
||||
RMDir /r $INSTDIR
|
||||
SectionEnd
|
|
@ -1,102 +0,0 @@
|
|||
!include "MUI2.nsh"
|
||||
|
||||
; Request administrative rights
|
||||
RequestExecutionLevel admin
|
||||
|
||||
; The name and file name of the installer
|
||||
Name "FreeData Server"
|
||||
OutFile "FreeData-Server-Installer.exe"
|
||||
|
||||
; Default installation directory
|
||||
; InstallDir "$PROGRAMFILES\FreeData\freedata-server"
|
||||
|
||||
InstallDir "$LOCALAPPDATA\FreeData\freedata-server"
|
||||
|
||||
; Registry key to store the installation directory
|
||||
InstallDirRegKey HKCU "Software\FreeData\freedata-server" "Install_Dir"
|
||||
|
||||
; Modern UI settings
|
||||
!define MUI_ABORTWARNING
|
||||
|
||||
; Installer interface settings
|
||||
!define MUI_ICON "documentation\icon.ico"
|
||||
!define MUI_UNICON "documentation\icon.ico" ; Icon for the uninstaller
|
||||
|
||||
|
||||
; Define the welcome page text
|
||||
!define MUI_WELCOMEPAGE_TEXT "Welcome to the FreeData Server Setup Wizard. This wizard will guide you through the installation process."
|
||||
!define MUI_FINISHPAGE_TEXT "Folder: $INSTDIR"
|
||||
|
||||
|
||||
!define MUI_DIRECTORYPAGE_TEXT_TOP "Please select the installation folder. Its recommended using the suggested one for avoiding permission problems."
|
||||
|
||||
|
||||
; Pages
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
!insertmacro MUI_PAGE_LICENSE "LICENSE"
|
||||
;!insertmacro MUI_PAGE_COMPONENTS
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
; Uninstaller
|
||||
!insertmacro MUI_UNPAGE_WELCOME
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
!insertmacro MUI_UNPAGE_FINISH
|
||||
|
||||
; Language (you can choose and configure the language(s) you want)
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
|
||||
; Installer Sections
|
||||
Section "FreeData Server" SEC01
|
||||
|
||||
; Set output path to the installation directory
|
||||
SetOutPath $INSTDIR
|
||||
|
||||
; Check if "config.ini" exists and back it up
|
||||
IfFileExists $INSTDIR\config.ini backupConfig
|
||||
|
||||
doneBackup:
|
||||
; Add your application files here
|
||||
File /r "modem\server.dist\*.*"
|
||||
|
||||
; Restore the original "config.ini" if it was backed up
|
||||
IfFileExists $INSTDIR\config.ini.bak restoreConfig
|
||||
|
||||
|
||||
|
||||
; Create a shortcut in the user's desktop
|
||||
CreateShortCut "$DESKTOP\FreeData Server.lnk" "$INSTDIR\freedata-server.exe"
|
||||
|
||||
; Create Uninstaller
|
||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||
|
||||
; Backup "config.ini" before overwriting files
|
||||
backupConfig:
|
||||
Rename $INSTDIR\config.ini $INSTDIR\config.ini.bak
|
||||
Goto doneBackup
|
||||
|
||||
; Restore the original "config.ini"
|
||||
restoreConfig:
|
||||
Delete $INSTDIR\config.ini
|
||||
Rename $INSTDIR\config.ini.bak $INSTDIR\config.ini
|
||||
|
||||
|
||||
SectionEnd
|
||||
|
||||
; Uninstaller Section
|
||||
Section "Uninstall"
|
||||
|
||||
; Delete files and directories
|
||||
Delete $INSTDIR\freedata-server.exe
|
||||
RMDir /r $INSTDIR
|
||||
|
||||
; Remove the shortcut
|
||||
Delete "$DESKTOP\FreeData Server.lnk"
|
||||
|
||||
; Additional uninstallation commands here
|
||||
|
||||
SectionEnd
|
||||
|
||||
|
|
@ -45,18 +45,12 @@
|
|||
"icon": "build/icon.png",
|
||||
"target": [
|
||||
{
|
||||
"target": "nsis",
|
||||
"target": "portable",
|
||||
"arch": ["arm64", "x64"]
|
||||
}
|
||||
],
|
||||
"artifactName": "${productName}-GUI-Windows-${version}.${ext}"
|
||||
},
|
||||
"nsis": {
|
||||
"oneClick": false,
|
||||
"perMachine": false,
|
||||
"allowToChangeInstallationDirectory": true,
|
||||
"deleteAppDataOnUninstall": true
|
||||
},
|
||||
"linux": {
|
||||
"category": "Development",
|
||||
"target": [
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { app, BrowserWindow, shell, ipcMain } from "electron";
|
||||
import { release, platform } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { autoUpdater } from "electron-updater";
|
||||
import { release, platform } from "os";
|
||||
import { join, dirname } from "path";
|
||||
import { existsSync } from "fs";
|
||||
import { spawn } from "child_process";
|
||||
|
||||
|
@ -20,7 +19,6 @@ process.env.DIST = join(process.env.DIST_ELECTRON, "../dist");
|
|||
process.env.VITE_PUBLIC = process.env.VITE_DEV_SERVER_URL
|
||||
? join(process.env.DIST_ELECTRON, "../public")
|
||||
: process.env.DIST;
|
||||
process.env.FDUpdateAvail = "0";
|
||||
|
||||
// Disable GPU Acceleration for Windows 7
|
||||
if (release().startsWith("6.1")) app.disableHardwareAcceleration();
|
||||
|
@ -40,7 +38,7 @@ if (!app.requestSingleInstanceLock()) {
|
|||
// process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'
|
||||
|
||||
// set daemon process var
|
||||
var daemonProcess = null;
|
||||
var serverProcess = null;
|
||||
let win: BrowserWindow | null = null;
|
||||
// Here, you can also use other preload
|
||||
const preload = join(__dirname, "../preload/index.js");
|
||||
|
@ -75,9 +73,9 @@ async function createWindow() {
|
|||
}
|
||||
|
||||
// Test actively push message to the Electron-Renderer
|
||||
win.webContents.on("did-finish-load", () => {
|
||||
win?.webContents.send("main-process-message", new Date().toLocaleString());
|
||||
});
|
||||
//win.webContents.on("did-finish-load", () => {
|
||||
// win?.webContents.send("main-process-message", new Date().toLocaleString());
|
||||
//});
|
||||
|
||||
// Make all links open with the browser, not with the application
|
||||
win.webContents.setWindowOpenHandler(({ url }) => {
|
||||
|
@ -87,12 +85,7 @@ async function createWindow() {
|
|||
// win.webContents.on('will-navigate', (event, url) => { }) #344
|
||||
|
||||
win.once("ready-to-show", () => {
|
||||
//autoUpdater.logger = log.scope("updater");
|
||||
//autoUpdater.channel = config.update_channel;
|
||||
autoUpdater.autoInstallOnAppQuit = false;
|
||||
autoUpdater.autoDownload = true;
|
||||
autoUpdater.checkForUpdatesAndNotify();
|
||||
//autoUpdater.quitAndInstall();
|
||||
//
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -102,68 +95,61 @@ app.whenReady().then(() => {
|
|||
|
||||
console.log(platform());
|
||||
//Generate daemon binary path
|
||||
var daemonPath = "";
|
||||
var serverPath = "";
|
||||
console.log(process.env);
|
||||
|
||||
// Attempt to find Installation Folder
|
||||
console.log(app.getAppPath());
|
||||
console.log(join(app.getAppPath(), "..", ".."));
|
||||
console.log(join(app.getAppPath(), "..", "..", ".."));
|
||||
|
||||
//var basePath = join(app.getAppPath(), '..', '..', '..') || join(process.env.PWD, '..') || join(process.env.INIT_CWD, '..') || join(process.env.DIST, '..', '..', '..');
|
||||
var basePath = join(app.getAppPath(), "..", "..", "..");
|
||||
switch (platform().toLowerCase()) {
|
||||
case "darwin":
|
||||
daemonPath = join(process.resourcesPath, "modem", "freedata-server");
|
||||
case "linux":
|
||||
daemonPath = join(process.resourcesPath, "modem", "freedata-server");
|
||||
break;
|
||||
//case "darwin":
|
||||
//serverPath = join(basePath, "freedata-server", "freedata-server.exe");
|
||||
//serverProcess = spawn(serverPath, [], { detached: true });
|
||||
//serverProcess.unref(); // Allow the server process to continue running independently of the parent process
|
||||
// break;
|
||||
//case "linux":
|
||||
//serverPath = join(basePath, "freedata-server", "freedata-server.exe");
|
||||
//serverProcess = spawn(serverPath, [], { detached: true });
|
||||
//serverProcess.unref(); // Allow the server process to continue running independently of the parent process
|
||||
// break;
|
||||
case "win32":
|
||||
daemonPath = join(process.resourcesPath, "modem", "freedata-server.exe");
|
||||
break;
|
||||
case "win64":
|
||||
daemonPath = join(process.resourcesPath, "modem", "freedata-server.exe");
|
||||
serverPath = join(basePath, "freedata-server", "freedata-server.exe");
|
||||
console.log(`Starting server with path: ${serverPath}`);
|
||||
serverProcess = spawn(
|
||||
"cmd.exe",
|
||||
["/c", "start", "cmd.exe", "/c", serverPath],
|
||||
{ shell: true },
|
||||
);
|
||||
console.log(`Started server | PID: ${serverProcess.pid}`);
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log("Unhandled OS Platform: ", platform());
|
||||
serverProcess = null;
|
||||
serverPath = null;
|
||||
break;
|
||||
}
|
||||
|
||||
//Start daemon binary if it exists
|
||||
if (existsSync(daemonPath)) {
|
||||
console.log("Starting freedata-server binary");
|
||||
console.log("daemonPath:", daemonPath);
|
||||
console.log("CWD:", join(daemonPath, ".."));
|
||||
/*
|
||||
var daemonProcess = spawn("freedata-server", [], {
|
||||
cwd: join(process.env.DIST, "modem"),
|
||||
shell: true
|
||||
serverProcess.on("error", (err) => {
|
||||
console.error("Failed to start server process:", err);
|
||||
serverProcess = null;
|
||||
serverPath = null;
|
||||
});
|
||||
*/
|
||||
/*
|
||||
daemonProcess = spawn(daemonPath, [], {
|
||||
shell: true
|
||||
serverProcess.stdout.on("data", (data) => {
|
||||
//console.log(`stdout: ${data}`);
|
||||
});
|
||||
console.log(daemonProcess)
|
||||
*/
|
||||
daemonProcess = spawn(daemonPath, [], {});
|
||||
|
||||
// return process messages
|
||||
daemonProcess.on("error", (err) => {
|
||||
//daemonProcessLog.error(`error when starting daemon: ${err}`);
|
||||
console.log(err);
|
||||
serverProcess.stderr.on("data", (data) => {
|
||||
console.error(`stderr: ${data}`);
|
||||
});
|
||||
daemonProcess.on("message", () => {
|
||||
// daemonProcessLog.info(`${data}`);
|
||||
});
|
||||
daemonProcess.stdout.on("data", () => {
|
||||
// daemonProcessLog.info(`${data}`);
|
||||
});
|
||||
daemonProcess.stderr.on("data", (data) => {
|
||||
// daemonProcessLog.info(`${data}`);
|
||||
console.log(data);
|
||||
});
|
||||
daemonProcess.on("close", (code) => {
|
||||
// daemonProcessLog.warn(`daemonProcess exited with code ${code}`);
|
||||
});
|
||||
} else {
|
||||
daemonProcess = null;
|
||||
daemonPath = null;
|
||||
console.log("Daemon binary doesn't exist--normal for dev environments.");
|
||||
}
|
||||
});
|
||||
|
||||
//)
|
||||
app.on("before-quit", () => {
|
||||
close_sub_processes();
|
||||
});
|
||||
|
||||
app.on("window-all-closed", () => {
|
||||
|
@ -205,104 +191,33 @@ ipcMain.handle("open-win", (_, arg) => {
|
|||
}
|
||||
});
|
||||
|
||||
//restart and install udpate
|
||||
ipcMain.on("request-restart-and-install-update", (event, data) => {
|
||||
close_sub_processes();
|
||||
autoUpdater.quitAndInstall();
|
||||
});
|
||||
|
||||
// LISTENER FOR UPDATER EVENTS
|
||||
autoUpdater.on("update-available", (info) => {
|
||||
process.env.FDUpdateAvail = "1";
|
||||
console.log("update available");
|
||||
|
||||
let arg = {
|
||||
status: "update-available",
|
||||
info: info,
|
||||
};
|
||||
win.webContents.send("action-updater", arg);
|
||||
});
|
||||
|
||||
autoUpdater.on("update-not-available", (info) => {
|
||||
console.log("update not available");
|
||||
let arg = {
|
||||
status: "update-not-available",
|
||||
info: info,
|
||||
};
|
||||
win.webContents.send("action-updater", arg);
|
||||
});
|
||||
|
||||
autoUpdater.on("update-downloaded", (info) => {
|
||||
process.env.FDUpdateAvail = "1";
|
||||
console.log("update downloaded");
|
||||
let arg = {
|
||||
status: "update-downloaded",
|
||||
info: info,
|
||||
};
|
||||
win.webContents.send("action-updater", arg);
|
||||
// we need to call this at this point.
|
||||
// if an update is available and we are force closing the app
|
||||
// the entire screen crashes...
|
||||
//console.log('quit application and install update');
|
||||
//autoUpdater.quitAndInstall();
|
||||
});
|
||||
|
||||
autoUpdater.on("checking-for-update", () => {
|
||||
console.log("checking for update");
|
||||
let arg = {
|
||||
status: "checking-for-update",
|
||||
version: app.getVersion(),
|
||||
};
|
||||
win.webContents.send("action-updater", arg);
|
||||
});
|
||||
|
||||
autoUpdater.on("download-progress", (progress) => {
|
||||
let arg = {
|
||||
status: "download-progress",
|
||||
progress: progress,
|
||||
};
|
||||
win.webContents.send("action-updater", arg);
|
||||
});
|
||||
|
||||
autoUpdater.on("error", (error) => {
|
||||
console.log("update error");
|
||||
let arg = {
|
||||
status: "error",
|
||||
progress: error,
|
||||
};
|
||||
win.webContents.send("action-updater", arg);
|
||||
console.log("AUTO UPDATER : " + error);
|
||||
});
|
||||
|
||||
function close_sub_processes() {
|
||||
console.log("closing sub processes");
|
||||
console.log("Closing sub processes...");
|
||||
|
||||
// closing the modem binary if not closed when closing application and also our daemon which has been started by the gui
|
||||
if (serverProcess != null) {
|
||||
try {
|
||||
if (daemonProcess != null) {
|
||||
daemonProcess.kill();
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
console.log(`Killing server process with PID: ${serverProcess.pid}`);
|
||||
|
||||
console.log("closing modem and daemon");
|
||||
try {
|
||||
if (platform() == "win32") {
|
||||
spawn("Taskkill", ["/IM", "freedata-modem.exe", "/F"]);
|
||||
spawn("Taskkill", ["/IM", "freedata-server.exe", "/F"]);
|
||||
}
|
||||
switch (platform().toLowerCase()) {
|
||||
//case "darwin":
|
||||
// process.kill(serverProcess.pid);
|
||||
// break;
|
||||
//case "linux":
|
||||
// process.kill(serverProcess.pid);
|
||||
// break;
|
||||
case "win32":
|
||||
// For Windows, use taskkill to ensure all child processes are also terminated
|
||||
spawn("taskkill", ["/pid", serverProcess.pid.toString(), "/f", "/t"]);
|
||||
break;
|
||||
|
||||
if (platform() == "linux") {
|
||||
spawn("pkill", ["-9", "freedata-modem"]);
|
||||
spawn("pkill", ["-9", "freedata-server"]);
|
||||
default:
|
||||
console.log("Unhandled OS Platform: ", platform());
|
||||
serverProcess = null;
|
||||
serverPath = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (platform() == "darwin") {
|
||||
spawn("pkill", ["-9", "freedata-modem"]);
|
||||
spawn("pkill", ["-9", "freedata-server"]);
|
||||
} catch (error) {
|
||||
console.error(`Error killing server process: ${error}`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,83 +111,4 @@ window.onmessage = (ev) => {
|
|||
ev.data.payload === "removeLoading" && removeLoading();
|
||||
};
|
||||
|
||||
setTimeout(removeLoading, 4999);
|
||||
|
||||
// IPC ACTION FOR AUTO UPDATER
|
||||
ipcRenderer.on("action-updater", (event, arg) => {
|
||||
if (arg.status == "download-progress") {
|
||||
var progressinfo =
|
||||
"(" +
|
||||
Math.round(arg.progress.transferred / 1024) +
|
||||
"kB /" +
|
||||
Math.round(arg.progress.total / 1024) +
|
||||
"kB)" +
|
||||
" @ " +
|
||||
Math.round(arg.progress.bytesPerSecond / 1024) +
|
||||
"kByte/s";
|
||||
document.getElementById("UpdateProgressInfo").innerHTML = progressinfo;
|
||||
|
||||
document
|
||||
.getElementById("UpdateProgressBar")
|
||||
.setAttribute("aria-valuenow", arg.progress.percent);
|
||||
document
|
||||
.getElementById("UpdateProgressBar")
|
||||
.setAttribute("style", "width:" + arg.progress.percent + "%;");
|
||||
}
|
||||
|
||||
if (arg.status == "checking-for-update") {
|
||||
//document.title = document.title + ' - v' + arg.version;
|
||||
//updateTitle(
|
||||
// config.myCall,
|
||||
// config.tnc_host,
|
||||
// config.tnc_port,
|
||||
// " -v " + arg.version,
|
||||
//);
|
||||
document.getElementById("updater_status").innerHTML =
|
||||
'<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>';
|
||||
|
||||
document.getElementById("updater_status").className =
|
||||
"btn btn-secondary btn-sm";
|
||||
document.getElementById("update_and_install").style.display = "none";
|
||||
}
|
||||
if (arg.status == "update-downloaded") {
|
||||
document.getElementById("update_and_install").removeAttribute("style");
|
||||
document.getElementById("updater_status").innerHTML =
|
||||
'<i class="bi bi-cloud-download ms-1 me-1" style="color: white;"></i>';
|
||||
document.getElementById("updater_status").className =
|
||||
"btn btn-success btn-sm";
|
||||
|
||||
// HERE WE NEED TO RUN THIS SOMEHOW...
|
||||
//mainLog.info('quit application and install update');
|
||||
//autoUpdater.quitAndInstall();
|
||||
}
|
||||
if (arg.status == "update-not-available") {
|
||||
document.getElementById("updater_last_version").innerHTML =
|
||||
arg.info.releaseName;
|
||||
document.getElementById("updater_last_update").innerHTML =
|
||||
arg.info.releaseDate;
|
||||
document.getElementById("updater_release_notes").innerHTML =
|
||||
arg.info.releaseNotes;
|
||||
|
||||
document.getElementById("updater_status").innerHTML =
|
||||
'<i class="bi bi-check2-square ms-1 me-1" style="color: white;"></i>';
|
||||
document.getElementById("updater_status").className =
|
||||
"btn btn-success btn-sm";
|
||||
document.getElementById("update_and_install").style.display = "none";
|
||||
}
|
||||
if (arg.status == "update-available") {
|
||||
document.getElementById("updater_status").innerHTML =
|
||||
'<i class="bi bi-hourglass-split ms-1 me-1" style="color: white;"></i>';
|
||||
document.getElementById("updater_status").className =
|
||||
"btn btn-warning btn-sm";
|
||||
document.getElementById("update_and_install").style.display = "none";
|
||||
}
|
||||
|
||||
if (arg.status == "error") {
|
||||
document.getElementById("updater_status").innerHTML =
|
||||
'<i class="bi bi-exclamation-square ms-1 me-1" style="color: white;"></i>';
|
||||
document.getElementById("updater_status").className =
|
||||
"btn btn-danger btn-sm";
|
||||
document.getElementById("update_and_install").style.display = "none";
|
||||
}
|
||||
});
|
||||
setTimeout(removeLoading, 3999);
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
"release": "vue-tsc --noEmit && vite build && electron-builder -p onTag",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint --ext .js,.vue src",
|
||||
"lint-fix": "eslint --ext .js,.vue --fix src"
|
||||
"lint-fix": "eslint --ext .js,.vue --fix src",
|
||||
"install-deps": "npm install && npm update"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
@ -21,15 +21,13 @@ import main_modem_healthcheck from "./main_modem_healthcheck.vue";
|
|||
import Dynamic_components from "./dynamic_components.vue";
|
||||
|
||||
import { getFreedataMessages } from "../js/api";
|
||||
import { getRemote } from "../store/settingsStore.js";
|
||||
import { loadAllData } from "../js/eventHandler";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-------------------------------- INFO TOASTS ---------------->
|
||||
<div
|
||||
aria-live="polite"
|
||||
aria-atomic="true"
|
||||
class="position-relative z-3"
|
||||
>
|
||||
<div aria-live="polite" aria-atomic="true" class="position-relative z-3">
|
||||
<div
|
||||
class="toast-container position-absolute top-0 end-0 p-3"
|
||||
id="mainToastContainer"
|
||||
|
@ -47,6 +45,7 @@ import { getFreedataMessages } from "../js/api";
|
|||
id="main-list-tab"
|
||||
role="tablist"
|
||||
style="margin-top: 100px"
|
||||
@click="loadAllData"
|
||||
>
|
||||
<main_modem_healthcheck />
|
||||
|
||||
|
@ -111,6 +110,7 @@ import { getFreedataMessages } from "../js/api";
|
|||
role="tab"
|
||||
aria-controls="list-settings"
|
||||
title="Settings"
|
||||
@click="loadAllData"
|
||||
><i class="bi bi-gear-wide-connected h3"></i
|
||||
></a>
|
||||
</div>
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
import { Modal } from "bootstrap";
|
||||
import { onMounted } from "vue";
|
||||
|
||||
import settings_updater_core from "./settings_updater_core.vue";
|
||||
|
||||
import { setActivePinia } from "pinia";
|
||||
import pinia from "../store/index";
|
||||
setActivePinia(pinia);
|
||||
|
@ -14,6 +12,11 @@ import { sendModemCQ } from "../js/api.js";
|
|||
import { useStateStore } from "../store/stateStore.js";
|
||||
const state = useStateStore(pinia);
|
||||
|
||||
import { useAudioStore } from "../store/audioStore";
|
||||
const audioStore = useAudioStore();
|
||||
import { useSerialStore } from "../store/serialStore";
|
||||
const serialStore = useSerialStore();
|
||||
|
||||
import {
|
||||
getVersion,
|
||||
setConfig,
|
||||
|
@ -21,11 +24,8 @@ import {
|
|||
stopModem,
|
||||
getModemState,
|
||||
} from "../js/api";
|
||||
import { audioInputOptions, audioOutputOptions } from "../js/deviceFormHelper";
|
||||
import { serialDeviceOptions } from "../js/deviceFormHelper";
|
||||
|
||||
const version = import.meta.env.PACKAGE_VERSION;
|
||||
var updateAvailable = process.env.FDUpdateAvail;
|
||||
|
||||
// start modemCheck modal once on startup
|
||||
onMounted(() => {
|
||||
|
@ -203,6 +203,7 @@ function testHamlib() {
|
|||
</button>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Audio Input Device -->
|
||||
<div class="input-group input-group-sm mb-1">
|
||||
<label class="input-group-text w-50"
|
||||
|
@ -215,10 +216,10 @@ function testHamlib() {
|
|||
v-model="settings.remote.AUDIO.input_device"
|
||||
>
|
||||
<option
|
||||
v-for="option in audioInputOptions()"
|
||||
v-bind:value="option.id"
|
||||
v-for="device in audioStore.audioInputs"
|
||||
:value="device.id"
|
||||
>
|
||||
{{ option.name }} [{{ option.api }}]
|
||||
{{ device.name }} [{{ device.api }}]
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -235,10 +236,10 @@ function testHamlib() {
|
|||
v-model="settings.remote.AUDIO.output_device"
|
||||
>
|
||||
<option
|
||||
v-for="option in audioOutputOptions()"
|
||||
v-bind:value="option.id"
|
||||
v-for="device in audioStore.audioOutputs"
|
||||
:value="device.id"
|
||||
>
|
||||
{{ option.name }} [{{ option.api }}]
|
||||
{{ device.name }} [{{ device.api }}]
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -310,18 +311,16 @@ function testHamlib() {
|
|||
>
|
||||
|
||||
<select
|
||||
class="form-select form-select-sm"
|
||||
aria-label=".form-select-sm"
|
||||
id="hamlib_deviceport"
|
||||
style="width: 7rem"
|
||||
@change="onChange"
|
||||
v-model="settings.remote.RADIO.serial_port"
|
||||
class="form-select form-select-sm"
|
||||
>
|
||||
<option
|
||||
v-for="option in serialDeviceOptions()"
|
||||
v-bind:value="option.port"
|
||||
v-for="device in serialStore.serialDevices"
|
||||
:value="device.port"
|
||||
:key="device.port"
|
||||
>
|
||||
{{ option.description }}
|
||||
{{ device.description }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -392,18 +391,6 @@ function testHamlib() {
|
|||
data-bs-toggle="collapse"
|
||||
>
|
||||
Version
|
||||
<span
|
||||
class="badge ms-2"
|
||||
:class="
|
||||
updateAvailable === '1' ? 'bg-warning' : 'bg-success'
|
||||
"
|
||||
>
|
||||
{{
|
||||
updateAvailable === "1"
|
||||
? "Update available ! ! ! !"
|
||||
: "Current"
|
||||
}}</span
|
||||
>
|
||||
</button>
|
||||
</h2>
|
||||
<div
|
||||
|
@ -426,9 +413,6 @@ function testHamlib() {
|
|||
>
|
||||
Modem version | {{ state.modem_version }}
|
||||
</button>
|
||||
<div :class="updateAvailable === '1' ? '' : 'd-none'">
|
||||
<settings_updater_core />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<script setup lang="ts">
|
||||
import settings_updater from "./settings_updater.vue";
|
||||
import settings_station from "./settings_station.vue";
|
||||
import settings_gui from "./settings_gui.vue";
|
||||
import settings_chat from "./settings_chat.vue";
|
||||
|
@ -23,20 +22,6 @@ import settings_exp from "./settings_exp.vue";
|
|||
<li class="nav-item" role="presentation">
|
||||
<button
|
||||
class="nav-link active"
|
||||
id="updater-tab"
|
||||
data-bs-toggle="tab"
|
||||
data-bs-target="#updater"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-controls="home"
|
||||
aria-selected="true"
|
||||
>
|
||||
Updater
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button
|
||||
class="nav-link"
|
||||
id="station-tab"
|
||||
data-bs-toggle="tab"
|
||||
data-bs-target="#station"
|
||||
|
@ -141,23 +126,10 @@ import settings_exp from "./settings_exp.vue";
|
|||
>
|
||||
<!-- SETTINGS Nav Tab panes -->
|
||||
|
||||
<!-- Updater tab contents-->
|
||||
<div class="tab-content">
|
||||
<div
|
||||
class="tab-pane active"
|
||||
id="updater"
|
||||
role="tabpanel"
|
||||
aria-labelledby="updater-tab"
|
||||
tabindex="0"
|
||||
>
|
||||
<settings_updater />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Station tab contents-->
|
||||
<div class="tab-content">
|
||||
<div
|
||||
class="tab-pane"
|
||||
class="tab-pane active"
|
||||
id="station"
|
||||
role="tabpanel"
|
||||
aria-labelledby="station-tab"
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { settingsStore as settings, onChange } from "../store/settingsStore.js";
|
||||
import { serialDeviceOptions } from "../js/deviceFormHelper";
|
||||
import { useSerialStore } from "../store/serialStore";
|
||||
const serialStore = useSerialStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -21,13 +22,13 @@ import { serialDeviceOptions } from "../js/deviceFormHelper";
|
|||
<div class="input-group input-group-sm mb-1">
|
||||
<span class="input-group-text" style="width: 180px">Rigctld port</span>
|
||||
<input
|
||||
type="text"
|
||||
type="number"
|
||||
class="form-control"
|
||||
placeholder="rigctld port"
|
||||
id="hamlib_rigctld_port"
|
||||
aria-label="Device Port"
|
||||
@change="onChange"
|
||||
v-model="settings.remote.RIGCTLD.port"
|
||||
v-model.number="settings.remote.RIGCTLD.port"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
@ -334,18 +335,16 @@ import { serialDeviceOptions } from "../js/deviceFormHelper";
|
|||
<span class="input-group-text" style="width: 180px">Radio port</span>
|
||||
|
||||
<select
|
||||
class="form-select form-select-sm"
|
||||
aria-label=".form-select-sm"
|
||||
id="hamlib_deviceport"
|
||||
style="width: 7rem"
|
||||
@change="onChange"
|
||||
v-model="settings.remote.RADIO.serial_port"
|
||||
class="form-select form-select-sm"
|
||||
>
|
||||
<option
|
||||
v-for="option in serialDeviceOptions()"
|
||||
v-bind:value="option.port"
|
||||
v-for="device in serialStore.serialDevices"
|
||||
:value="device.port"
|
||||
:key="device.port"
|
||||
>
|
||||
{{ option.description }}
|
||||
{{ device.description }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -422,18 +421,18 @@ import { serialDeviceOptions } from "../js/deviceFormHelper";
|
|||
|
||||
<div class="input-group input-group-sm mb-1">
|
||||
<span class="input-group-text" style="width: 180px">PTT device port</span>
|
||||
|
||||
<select
|
||||
class="form-select form-select-sm"
|
||||
aria-label=".form-select-sm"
|
||||
id="hamlib_ptt_port"
|
||||
@change="onChange"
|
||||
v-model="settings.remote.RADIO.ptt_port"
|
||||
class="form-select form-select-sm"
|
||||
>
|
||||
<option
|
||||
v-for="option in serialDeviceOptions()"
|
||||
v-bind:value="option.port"
|
||||
v-for="device in serialStore.serialDevices"
|
||||
:value="device.port"
|
||||
:key="device.port"
|
||||
>
|
||||
{{ option.description }}
|
||||
{{ device.description }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,9 @@ import { useStateStore } from "../store/stateStore.js";
|
|||
const state = useStateStore(pinia);
|
||||
|
||||
import { startModem, stopModem } from "../js/api.js";
|
||||
import { audioInputOptions, audioOutputOptions } from "../js/deviceFormHelper";
|
||||
|
||||
import { useAudioStore } from "../store/audioStore";
|
||||
const audioStore = useAudioStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -74,8 +76,8 @@ import { audioInputOptions, audioOutputOptions } from "../js/deviceFormHelper";
|
|||
@change="onChange"
|
||||
v-model="settings.remote.AUDIO.input_device"
|
||||
>
|
||||
<option v-for="option in audioInputOptions()" v-bind:value="option.id">
|
||||
{{ option.name }} [{{ option.api }}]
|
||||
<option v-for="device in audioStore.audioInputs" :value="device.id">
|
||||
{{ device.name }} [{{ device.api }}]
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -89,11 +91,12 @@ import { audioInputOptions, audioOutputOptions } from "../js/deviceFormHelper";
|
|||
@change="onChange"
|
||||
v-model="settings.remote.AUDIO.output_device"
|
||||
>
|
||||
<option v-for="option in audioOutputOptions()" v-bind:value="option.id">
|
||||
{{ option.name }} [{{ option.api }}]
|
||||
<option v-for="device in audioStore.audioOutputs" :value="device.id">
|
||||
{{ device.name }} [{{ device.api }}]
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Audio rx level-->
|
||||
<div class="input-group input-group-sm mb-1">
|
||||
<span class="input-group-text w-25">RX Audio Level</span>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { settingsStore as settings, onChange } from "../store/settingsStore.js";
|
||||
import { serialDeviceOptions } from "../js/deviceFormHelper";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import settings_updater_core from "./settings_updater_core.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="alert alert-warning" role="alert">
|
||||
The updater might not working, yet! Please update manually if you are running into problems!
|
||||
</div>
|
||||
<div class="alert alert-warning" role="alert">
|
||||
The updater doesnt contain the server related parts, yet! We are discussing this topic actually, feel free contributing with your opinion on Discord!
|
||||
</div>
|
||||
|
||||
<settings_updater_core />
|
||||
</div>
|
||||
</template>
|
|
@ -1,102 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import { setActivePinia } from "pinia";
|
||||
import pinia from "../store/index";
|
||||
setActivePinia(pinia);
|
||||
|
||||
import { useStateStore } from "../store/stateStore.js";
|
||||
import { settingsStore } from "../store/settingsStore";
|
||||
import { onMounted } from "vue";
|
||||
import { ipcRenderer } from "electron";
|
||||
const state = useStateStore(pinia);
|
||||
onMounted(() => {
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
// we are using this area for implementing the electron runUpdater
|
||||
// we need access to DOM for displaying updater results in GUI
|
||||
// close app, update and restart
|
||||
document
|
||||
.getElementById("update_and_install")
|
||||
.addEventListener("click", () => {
|
||||
ipcRenderer.send("request-restart-and-install-update");
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="card m-2">
|
||||
<div class="card-header p-1 d-flex">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-1">
|
||||
<i class="bi bi-cloud-download" style="font-size: 1.2rem"></i>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<strong class="fs-5">Updater</strong>
|
||||
</div>
|
||||
<div class="col-7">
|
||||
<div class="progress w-100 ms-1 m-1">
|
||||
<div
|
||||
class="progress-bar"
|
||||
style="width: 0%"
|
||||
role="progressbar"
|
||||
id="UpdateProgressBar"
|
||||
aria-valuenow="0"
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="100"
|
||||
>
|
||||
<span id="UpdateProgressInfo"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-1 text-end">
|
||||
<button
|
||||
type="button"
|
||||
id="openHelpModalUpdater"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#updaterHelpModal"
|
||||
class="btn m-0 p-0 border-0"
|
||||
>
|
||||
<i class="bi bi-question-circle" style="font-size: 1rem"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body p-2 mb-1">
|
||||
<button
|
||||
class="btn btn-secondary btn-sm ms-1 me-1"
|
||||
id="updater_channel"
|
||||
type="button"
|
||||
disabled
|
||||
>
|
||||
Update channel: {{ settingsStore.local.update_channel }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm ms-1"
|
||||
id="updater_status"
|
||||
type="button"
|
||||
disabled
|
||||
>
|
||||
...
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm ms-1"
|
||||
id="updater_changelog"
|
||||
type="button"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#updaterReleaseNotes"
|
||||
>
|
||||
Changelog
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-primary btn-sm ms-1"
|
||||
id="update_and_install"
|
||||
type="button"
|
||||
style="display: none"
|
||||
>
|
||||
Install & Restart
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
|
@ -1,53 +0,0 @@
|
|||
import { getAudioDevices, getSerialDevices } from "./api";
|
||||
|
||||
let audioDevices = await getAudioDevices();
|
||||
let serialDevices = await getSerialDevices();
|
||||
|
||||
//Dummy device data sent if unable to get devices from modem to prevent GUI crash
|
||||
const skel = JSON.parse(`
|
||||
[{
|
||||
"api": "MME",
|
||||
"id": "0000",
|
||||
"name": "No devices received from modem",
|
||||
"native_index": 0
|
||||
}]`);
|
||||
|
||||
export function loadAudioDevices() {
|
||||
getAudioDevices().then((devices) => {
|
||||
audioDevices = devices;
|
||||
});
|
||||
}
|
||||
|
||||
export function loadSerialDevices() {
|
||||
getSerialDevices().then((devices) => {
|
||||
serialDevices = devices;
|
||||
});
|
||||
}
|
||||
|
||||
export function audioInputOptions() {
|
||||
if (audioDevices === undefined) {
|
||||
return skel;
|
||||
}
|
||||
return audioDevices.in;
|
||||
}
|
||||
|
||||
export function audioOutputOptions() {
|
||||
if (audioDevices === undefined) {
|
||||
return skel;
|
||||
}
|
||||
|
||||
return audioDevices.out;
|
||||
}
|
||||
|
||||
export function serialDeviceOptions() {
|
||||
//Return ignore option if no serialDevices
|
||||
if (serialDevices === undefined)
|
||||
return [{ description: "-- ignore --", port: "ignore" }];
|
||||
|
||||
if (serialDevices.findIndex((device) => device.port == "ignore") == -1) {
|
||||
//Add an ignore option for rig and ptt for transceivers that don't require them
|
||||
serialDevices.push({ description: "-- ignore --", port: "ignore" });
|
||||
}
|
||||
|
||||
return serialDevices;
|
||||
}
|
|
@ -8,16 +8,15 @@ import {
|
|||
} from "./chatHandler";
|
||||
*/
|
||||
import { displayToast } from "./popupHandler";
|
||||
import {
|
||||
getFreedataMessages,
|
||||
getConfig,
|
||||
getAudioDevices,
|
||||
getSerialDevices,
|
||||
getModemState,
|
||||
} from "./api";
|
||||
import { getFreedataMessages, getModemState, getAudioDevices } from "./api";
|
||||
import { processFreedataMessages } from "./messagesHandler.ts";
|
||||
import { processRadioStatus } from "./radioHandler.ts";
|
||||
|
||||
import { useAudioStore } from "../store/audioStore";
|
||||
const audioStore = useAudioStore();
|
||||
import { useSerialStore } from "../store/serialStore";
|
||||
const serialStore = useSerialStore();
|
||||
|
||||
// ----------------- init pinia stores -------------
|
||||
import { setActivePinia } from "pinia";
|
||||
import pinia from "../store/index";
|
||||
|
@ -30,6 +29,17 @@ import {
|
|||
getRemote,
|
||||
} from "../store/settingsStore.js";
|
||||
|
||||
export function loadAllData() {
|
||||
getModemState();
|
||||
getRemote();
|
||||
getOverallHealth();
|
||||
audioStore.loadAudioDevices();
|
||||
serialStore.loadSerialDevices();
|
||||
getFreedataMessages();
|
||||
processFreedataMessages();
|
||||
processRadioStatus();
|
||||
}
|
||||
|
||||
export function connectionFailed(endpoint, event) {
|
||||
stateStore.modem_connection = "disconnected";
|
||||
}
|
||||
|
@ -95,12 +105,7 @@ export function eventDispatcher(data) {
|
|||
switch (data["modem"]) {
|
||||
case "started":
|
||||
displayToast("success", "bi-arrow-left-right", "Modem started", 5000);
|
||||
getModemState();
|
||||
getConfig();
|
||||
getAudioDevices();
|
||||
getSerialDevices();
|
||||
getFreedataMessages();
|
||||
processRadioStatus();
|
||||
loadAllData();
|
||||
return;
|
||||
|
||||
case "stopped":
|
||||
|
@ -109,12 +114,7 @@ export function eventDispatcher(data) {
|
|||
|
||||
case "restarted":
|
||||
displayToast("secondary", "bi-bootstrap-reboot", "Modem restarted", 5000);
|
||||
getModemState();
|
||||
getConfig();
|
||||
getAudioDevices();
|
||||
getSerialDevices();
|
||||
getFreedataMessages();
|
||||
processRadioStatus();
|
||||
loadAllData();
|
||||
return;
|
||||
|
||||
case "failed":
|
||||
|
@ -135,19 +135,7 @@ export function eventDispatcher(data) {
|
|||
displayToast("success", "bi-ethernet", message, 5000);
|
||||
stateStore.modem_connection = "connected";
|
||||
|
||||
getRemote().then(() => {
|
||||
//initConnections();
|
||||
getModemState();
|
||||
});
|
||||
|
||||
//getConfig();
|
||||
getModemState();
|
||||
getOverallHealth();
|
||||
getAudioDevices();
|
||||
getSerialDevices();
|
||||
getFreedataMessages();
|
||||
processFreedataMessages();
|
||||
processRadioStatus();
|
||||
loadAllData();
|
||||
|
||||
return;
|
||||
|
||||
|
|
39
gui/src/store/audioStore.js
Normal file
39
gui/src/store/audioStore.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { getAudioDevices } from "../js/api";
|
||||
import { ref } from "vue";
|
||||
|
||||
// Define skel fallback data
|
||||
const skel = [
|
||||
{
|
||||
api: "ERR",
|
||||
id: "0000",
|
||||
name: "No devices received from modem",
|
||||
native_index: 0,
|
||||
},
|
||||
];
|
||||
|
||||
export const useAudioStore = defineStore("audioStore", () => {
|
||||
const audioInputs = ref([]);
|
||||
const audioOutputs = ref([]);
|
||||
|
||||
const loadAudioDevices = async () => {
|
||||
try {
|
||||
const devices = await getAudioDevices();
|
||||
// Check if devices are valid and have entries, otherwise use skel
|
||||
audioInputs.value = devices && devices.in.length > 0 ? devices.in : skel;
|
||||
audioOutputs.value =
|
||||
devices && devices.out.length > 0 ? devices.out : skel;
|
||||
} catch (error) {
|
||||
console.error("Failed to load audio devices:", error);
|
||||
// Use skel as fallback in case of error
|
||||
audioInputs.value = skel;
|
||||
audioOutputs.value = skel;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
audioInputs,
|
||||
audioOutputs,
|
||||
loadAudioDevices,
|
||||
};
|
||||
});
|
38
gui/src/store/serialStore.js
Normal file
38
gui/src/store/serialStore.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { getSerialDevices } from "../js/api"; // Make sure this points to the correct file
|
||||
import { ref } from "vue";
|
||||
|
||||
// Define "skel" fallback data for serial devices
|
||||
const skelSerial = [
|
||||
{
|
||||
description: "No devices received from modem",
|
||||
port: "ignore", // Using "ignore" as a placeholder value
|
||||
},
|
||||
];
|
||||
|
||||
export const useSerialStore = defineStore("serialStore", () => {
|
||||
const serialDevices = ref([]);
|
||||
|
||||
const loadSerialDevices = async () => {
|
||||
try {
|
||||
const devices = await getSerialDevices();
|
||||
// Check if devices are valid and have entries, otherwise use skelSerial
|
||||
serialDevices.value =
|
||||
devices && devices.length > 0 ? devices : skelSerial;
|
||||
} catch (error) {
|
||||
console.error("Failed to load serial devices:", error);
|
||||
// Use skelSerial as fallback in case of error
|
||||
serialDevices.value = skelSerial;
|
||||
}
|
||||
|
||||
// Ensure the "-- ignore --" option is always available
|
||||
if (!serialDevices.value.some((device) => device.port === "ignore")) {
|
||||
serialDevices.value.push({ description: "-- ignore --", port: "ignore" });
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
serialDevices,
|
||||
loadSerialDevices,
|
||||
};
|
||||
});
|
|
@ -74,23 +74,20 @@ def freedv_get_mode_name_by_value(mode: int) -> str:
|
|||
return FREEDV_MODE(mode).name
|
||||
|
||||
|
||||
# Check if we are running in a pyinstaller environment
|
||||
#if hasattr(sys, "_MEIPASS"):
|
||||
# sys.path.append(getattr(sys, "_MEIPASS"))
|
||||
#else:
|
||||
sys.path.append(os.path.abspath("."))
|
||||
|
||||
#log.info("[C2 ] Searching for libcodec2...")
|
||||
# Get the directory of the current script file
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.append(script_dir)
|
||||
# Use script_dir to construct the paths for file search
|
||||
if sys.platform == "linux":
|
||||
files = glob.glob(r"**/*libcodec2*", recursive=True)
|
||||
files.append("libcodec2.so")
|
||||
files = glob.glob(os.path.join(script_dir, "**/*libcodec2*"), recursive=True)
|
||||
files.append(os.path.join(script_dir, "libcodec2.so"))
|
||||
elif sys.platform == "darwin":
|
||||
if hasattr(sys, "_MEIPASS"):
|
||||
files = glob.glob(getattr(sys, "_MEIPASS") + '/**/*libcodec2*', recursive=True)
|
||||
files = glob.glob(os.path.join(getattr(sys, "_MEIPASS"), '**/*libcodec2*'), recursive=True)
|
||||
else:
|
||||
files = glob.glob(r"**/*libcodec2*.dylib", recursive=True)
|
||||
files = glob.glob(os.path.join(script_dir, "**/*libcodec2*.dylib"), recursive=True)
|
||||
elif sys.platform in ["win32", "win64"]:
|
||||
files = glob.glob(r"**\*libcodec2*.dll", recursive=True)
|
||||
files = glob.glob(os.path.join(script_dir, "**\\*libcodec2*.dll"), recursive=True)
|
||||
else:
|
||||
files = []
|
||||
|
||||
|
|
|
@ -2,12 +2,16 @@ from message_system_db_manager import DatabaseManager
|
|||
from message_system_db_model import MessageAttachment, Attachment, P2PMessage
|
||||
import json
|
||||
import hashlib
|
||||
|
||||
import os
|
||||
|
||||
|
||||
class DatabaseManagerAttachments(DatabaseManager):
|
||||
def __init__(self, uri='sqlite:///freedata-messages.db'):
|
||||
super().__init__(uri)
|
||||
def __init__(self, db_file=None):
|
||||
if not db_file:
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
db_path = os.path.join(script_dir, 'freedata-messages.db')
|
||||
db_file = 'sqlite:///' + db_path
|
||||
super().__init__(db_file)
|
||||
|
||||
|
||||
def add_attachment(self, session, message, attachment_data):
|
||||
|
|
|
@ -4,14 +4,16 @@ from sqlalchemy.orm import scoped_session, sessionmaker
|
|||
from threading import local
|
||||
from message_system_db_model import Base, Beacon, Station, Status, Attachment, P2PMessage
|
||||
from datetime import timezone, timedelta, datetime
|
||||
import json
|
||||
import structlog
|
||||
import helpers
|
||||
|
||||
import os
|
||||
|
||||
class DatabaseManagerBeacon(DatabaseManager):
|
||||
def __init__(self, uri):
|
||||
super().__init__(uri)
|
||||
def __init__(self, db_file=None):
|
||||
if not db_file:
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
db_path = os.path.join(script_dir, 'freedata-messages.db')
|
||||
db_file = 'sqlite:///' + db_path
|
||||
|
||||
super().__init__(db_file)
|
||||
|
||||
def add_beacon(self, timestamp, callsign, snr, gridsquare):
|
||||
session = None
|
||||
|
|
|
@ -7,12 +7,17 @@ from threading import local
|
|||
from message_system_db_model import Base, Station, Status
|
||||
import structlog
|
||||
import helpers
|
||||
import os
|
||||
|
||||
class DatabaseManager:
|
||||
def __init__(self, event_manger, uri='sqlite:///freedata-messages.db'):
|
||||
def __init__(self, event_manger, db_file=None):
|
||||
self.event_manager = event_manger
|
||||
if not db_file:
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
db_path = os.path.join(script_dir, 'freedata-messages.db')
|
||||
db_file = 'sqlite:///' + db_path
|
||||
|
||||
self.engine = create_engine(uri, echo=False)
|
||||
self.engine = create_engine(db_file, echo=False)
|
||||
self.thread_local = local()
|
||||
self.session_factory = sessionmaker(bind=self.engine)
|
||||
Base.metadata.create_all(self.engine)
|
||||
|
|
|
@ -4,12 +4,18 @@ from message_system_db_model import Status, P2PMessage
|
|||
from sqlalchemy.exc import IntegrityError
|
||||
from datetime import datetime
|
||||
import json
|
||||
import os
|
||||
|
||||
|
||||
class DatabaseManagerMessages(DatabaseManager):
|
||||
def __init__(self, uri='sqlite:///freedata-messages.db'):
|
||||
super().__init__(uri)
|
||||
self.attachments_manager = DatabaseManagerAttachments(uri)
|
||||
def __init__(self, db_file=None):
|
||||
if not db_file:
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
db_path = os.path.join(script_dir, 'freedata-messages.db')
|
||||
db_file = 'sqlite:///' + db_path
|
||||
|
||||
super().__init__(db_file)
|
||||
self.attachments_manager = DatabaseManagerAttachments(db_file)
|
||||
|
||||
def add_message(self, message_data, statistics, direction='receive', status=None, is_read=True):
|
||||
session = self.get_thread_scoped_session()
|
||||
|
|
|
@ -36,7 +36,8 @@ def set_config():
|
|||
if 'FREEDATA_CONFIG' in os.environ:
|
||||
config_file = os.environ['FREEDATA_CONFIG']
|
||||
else:
|
||||
config_file = 'config.ini'
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
config_file = os.path.join(script_dir, 'config.ini')
|
||||
|
||||
if os.path.exists(config_file):
|
||||
print(f"Using config from {config_file}")
|
||||
|
|
Loading…
Reference in a new issue