Compare commits
2 Commits
9a68358432
...
3ca730ecee
| Author | SHA1 | Date | |
|---|---|---|---|
| 3ca730ecee | |||
| cb799ae8b7 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -137,6 +137,7 @@ build
|
|||||||
.nova
|
.nova
|
||||||
|
|
||||||
temp_files/*
|
temp_files/*
|
||||||
|
data/*
|
||||||
|
|
||||||
dist/*
|
dist/*
|
||||||
|
|
||||||
|
|||||||
98
src/commandline.js
Normal file
98
src/commandline.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import {
|
||||||
|
authenticateWithOtp,
|
||||||
|
checkRunning,
|
||||||
|
isInfo,
|
||||||
|
otpCode,
|
||||||
|
printAuthCommand,
|
||||||
|
printerHostInfo,
|
||||||
|
startWaiting,
|
||||||
|
stopWaiting,
|
||||||
|
} from "./commandlineutils.js";
|
||||||
|
|
||||||
|
export async function handleCommandLine(cli, logger) {
|
||||||
|
const isCommandLines = otpCode != undefined || isInfo == true;
|
||||||
|
let runningServer;
|
||||||
|
try {
|
||||||
|
startWaiting("Checking if Farm Control Server is running...", logger);
|
||||||
|
runningServer = await checkRunning();
|
||||||
|
await stopWaiting();
|
||||||
|
if (runningServer == false && isCommandLines == true) {
|
||||||
|
cli.failure("Farm Control Server is not running.");
|
||||||
|
cli.blank();
|
||||||
|
return { handled: true, result: false };
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
await stopWaiting();
|
||||||
|
cli.failure("Failed to check if Farm Control Server is running:", err);
|
||||||
|
cli.blank();
|
||||||
|
return { handled: true, result: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCommandLines == true) {
|
||||||
|
cli.success("Farm Control Server is running.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isInfo) {
|
||||||
|
const buildNumber =
|
||||||
|
runningServer.buildNumber ?? runningServer.build ?? "n/a";
|
||||||
|
cli.blank();
|
||||||
|
cli.sectionHeader("FarmControl Server");
|
||||||
|
cli.label(
|
||||||
|
"Version:",
|
||||||
|
runningServer.version ? `v${runningServer.version}` : "n/a",
|
||||||
|
);
|
||||||
|
cli.label("Build:", buildNumber === "dev" ? "dev" : `b${buildNumber}`);
|
||||||
|
cli.label("Config:", runningServer.configPath || "n/a");
|
||||||
|
cli.label("Data Dir:", runningServer.dataDir || "n/a");
|
||||||
|
cli.label("Connected:", cli.yesNo(runningServer.connected == true));
|
||||||
|
cli.label("Authenticated:", cli.yesNo(runningServer.authenticated == true));
|
||||||
|
cli.sectionFooter();
|
||||||
|
cli.blank();
|
||||||
|
if (
|
||||||
|
runningServer.authenticated == false &&
|
||||||
|
runningServer.connected == true
|
||||||
|
) {
|
||||||
|
cli.sectionHeader("Authenticate");
|
||||||
|
printAuthCommand(cli);
|
||||||
|
cli.sectionFooter();
|
||||||
|
} else if (
|
||||||
|
runningServer.connected == true &&
|
||||||
|
runningServer.authenticated == true
|
||||||
|
) {
|
||||||
|
cli.sectionHeader("Host");
|
||||||
|
printerHostInfo(runningServer.host, cli);
|
||||||
|
cli.sectionFooter();
|
||||||
|
}
|
||||||
|
cli.blank();
|
||||||
|
return { handled: true, result: runningServer };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otpCode != undefined) {
|
||||||
|
cli.blank();
|
||||||
|
startWaiting("Authenticating with OTP...", logger);
|
||||||
|
let authenticatedServer;
|
||||||
|
try {
|
||||||
|
authenticatedServer = await authenticateWithOtp(otpCode);
|
||||||
|
await stopWaiting();
|
||||||
|
} catch (err) {
|
||||||
|
await stopWaiting();
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
if (authenticatedServer.valid == false) {
|
||||||
|
cli.failure("Failed to authenticate!");
|
||||||
|
cli.failure(authenticatedServer.error);
|
||||||
|
} else {
|
||||||
|
cli.success("Authenticated with OTP.");
|
||||||
|
cli.blank();
|
||||||
|
cli.sectionHeader("Host");
|
||||||
|
printerHostInfo(authenticatedServer.host, cli);
|
||||||
|
cli.sectionFooter();
|
||||||
|
cli.blank();
|
||||||
|
return { handled: true, result: authenticatedServer };
|
||||||
|
}
|
||||||
|
cli.blank();
|
||||||
|
return { handled: true, result: authenticatedServer };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { handled: false, runningServer };
|
||||||
|
}
|
||||||
@ -79,6 +79,57 @@ const CONFIG_PATH =
|
|||||||
const logger = log4js.getLogger("Config");
|
const logger = log4js.getLogger("Config");
|
||||||
logger.level = "info";
|
logger.level = "info";
|
||||||
|
|
||||||
|
function getDefaultProductionDataDir() {
|
||||||
|
const homeDir = process.env.HOME || process.env.USERPROFILE || "";
|
||||||
|
switch (process.platform) {
|
||||||
|
case "win32":
|
||||||
|
return path.join(
|
||||||
|
process.env.PROGRAMDATA || "C:\\ProgramData",
|
||||||
|
"farmcontrol-server",
|
||||||
|
"data",
|
||||||
|
);
|
||||||
|
case "darwin":
|
||||||
|
return path.join(
|
||||||
|
homeDir,
|
||||||
|
"Library",
|
||||||
|
"Application Support",
|
||||||
|
"farmcontrol-server",
|
||||||
|
"data",
|
||||||
|
);
|
||||||
|
case "linux":
|
||||||
|
default:
|
||||||
|
return "/var/lib/farmcontrol-server";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDefaultDevelopmentDataDir() {
|
||||||
|
if (isPackaged) {
|
||||||
|
return path.join(path.dirname(getDevelopmentConfigPath()), "data");
|
||||||
|
}
|
||||||
|
return path.resolve(__dirname, "../data");
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveDataDir(envConfig) {
|
||||||
|
let dataDir = envConfig.dataDir;
|
||||||
|
const wasMissing = !dataDir;
|
||||||
|
|
||||||
|
if (!dataDir) {
|
||||||
|
dataDir =
|
||||||
|
NODE_ENV === "production"
|
||||||
|
? getDefaultProductionDataDir()
|
||||||
|
: getDefaultDevelopmentDataDir();
|
||||||
|
}
|
||||||
|
|
||||||
|
dataDir = path.resolve(dataDir);
|
||||||
|
|
||||||
|
if (!fs.existsSync(dataDir)) {
|
||||||
|
fs.mkdirSync(dataDir, { recursive: true });
|
||||||
|
logger.info(`Created data directory at ${dataDir}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { dataDir, shouldPersist: wasMissing && NODE_ENV === "production" };
|
||||||
|
}
|
||||||
|
|
||||||
const DEFAULT_CONFIG = {
|
const DEFAULT_CONFIG = {
|
||||||
development: {
|
development: {
|
||||||
logLevel: "debug",
|
logLevel: "debug",
|
||||||
@ -127,6 +178,14 @@ export function loadConfig() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { dataDir, shouldPersist } = resolveDataDir(config[NODE_ENV]);
|
||||||
|
config[NODE_ENV] = { ...config[NODE_ENV], dataDir };
|
||||||
|
|
||||||
|
if (shouldPersist) {
|
||||||
|
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), "utf8");
|
||||||
|
logger.info(`Set data directory to ${dataDir} in config`);
|
||||||
|
}
|
||||||
|
|
||||||
return config[NODE_ENV];
|
return config[NODE_ENV];
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error("Error loading config:", err);
|
logger.error("Error loading config:", err);
|
||||||
@ -167,3 +226,25 @@ export async function saveConfig(newConfig) {
|
|||||||
export function getEnvironment() {
|
export function getEnvironment() {
|
||||||
return NODE_ENV;
|
return NODE_ENV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the path to the active config.json file
|
||||||
|
export function getConfigPath() {
|
||||||
|
return CONFIG_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the configured data directory, optionally with subpaths
|
||||||
|
export function getDataDir(...subpaths) {
|
||||||
|
const config = loadConfig();
|
||||||
|
return subpaths.length > 0
|
||||||
|
? path.join(config.dataDir, ...subpaths)
|
||||||
|
: config.dataDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure a subdirectory exists within the data directory
|
||||||
|
export function ensureDataDir(...subpaths) {
|
||||||
|
const dir = getDataDir(...subpaths);
|
||||||
|
if (!fs.existsSync(dir)) {
|
||||||
|
fs.mkdirSync(dir, { recursive: true });
|
||||||
|
}
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
// filemanager.js - Manages file downloads and caching
|
// filemanager.js - Manages file downloads and caching
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { fileURLToPath } from "url";
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import log4js from "log4js";
|
import log4js from "log4js";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { loadConfig } from "../config.js";
|
import { loadConfig, ensureDataDir } from "../config.js";
|
||||||
import { sendIPC } from "../electron/ipc.js";
|
import { sendIPC } from "../electron/ipc.js";
|
||||||
|
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
@ -13,31 +12,25 @@ const config = loadConfig();
|
|||||||
const logger = log4js.getLogger("File Manager");
|
const logger = log4js.getLogger("File Manager");
|
||||||
logger.level = config.logLevel;
|
logger.level = config.logLevel;
|
||||||
|
|
||||||
// Configure paths relative to this file
|
const FILES_DIR = ensureDataDir("files");
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
|
||||||
const __dirname = path.dirname(__filename);
|
|
||||||
const TEMP_FILES_DIR = path.resolve(__dirname, "../../temp_files");
|
|
||||||
|
|
||||||
export class FileManager {
|
export class FileManager {
|
||||||
constructor(socketClient) {
|
constructor(socketClient) {
|
||||||
this.socketClient = socketClient;
|
this.socketClient = socketClient;
|
||||||
this.files = [];
|
this.files = [];
|
||||||
this.downloadingFiles = new Map(); // Track ongoing downloads by fileId
|
this.downloadingFiles = new Map(); // Track ongoing downloads by fileId
|
||||||
this.ensureTempFilesDirectory();
|
this.ensureFilesDirectory();
|
||||||
this.progressCallbacks = new Map();
|
this.progressCallbacks = new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure the temp_files directory exists
|
* Ensure the files directory exists within the data directory
|
||||||
*/
|
*/
|
||||||
ensureTempFilesDirectory() {
|
ensureFilesDirectory() {
|
||||||
try {
|
try {
|
||||||
if (!fs.existsSync(TEMP_FILES_DIR)) {
|
ensureDataDir("files");
|
||||||
fs.mkdirSync(TEMP_FILES_DIR, { recursive: true });
|
|
||||||
logger.info(`Created temp_files directory at ${TEMP_FILES_DIR}`);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Failed to create temp_files directory: ${error.message}`);
|
logger.error(`Failed to create files directory: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,14 +63,14 @@ export class FileManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the file path in temp_files directory
|
* Get the file path in the files directory
|
||||||
*/
|
*/
|
||||||
getFilePath(fileId) {
|
getFilePath(fileId) {
|
||||||
return path.join(TEMP_FILES_DIR, fileId);
|
return path.join(FILES_DIR, fileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if file exists in temp_files directory
|
* Check if file exists in the files directory
|
||||||
*/
|
*/
|
||||||
fileExistsInCache(fileId) {
|
fileExistsInCache(fileId) {
|
||||||
const filePath = this.getFilePath(fileId);
|
const filePath = this.getFilePath(fileId);
|
||||||
@ -201,7 +194,7 @@ export class FileManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get file by ID
|
* Get file by ID
|
||||||
* Checks temp_files directory first, then downloads from API if not found
|
* Checks the files directory first, then downloads from API if not found
|
||||||
* If a download is already in progress for the same fileId, waits for that download
|
* If a download is already in progress for the same fileId, waits for that download
|
||||||
*/
|
*/
|
||||||
async getFile(fileId, onProgress) {
|
async getFile(fileId, onProgress) {
|
||||||
|
|||||||
84
src/index.js
84
src/index.js
@ -7,17 +7,12 @@ import { setupIPC } from "./electron/ipc.js";
|
|||||||
import { LocalServer } from "./localserver/localserver.js";
|
import { LocalServer } from "./localserver/localserver.js";
|
||||||
import { SocketClient } from "./socket/socketclient.js";
|
import { SocketClient } from "./socket/socketclient.js";
|
||||||
import {
|
import {
|
||||||
authenticateWithOtp,
|
|
||||||
checkRunning,
|
|
||||||
createCliLogger,
|
createCliLogger,
|
||||||
isHeadless,
|
isHeadless,
|
||||||
isInfo,
|
|
||||||
otpCode,
|
|
||||||
printAuthCommand,
|
|
||||||
printerHostInfo,
|
|
||||||
startWaiting,
|
startWaiting,
|
||||||
stopWaiting,
|
stopWaiting,
|
||||||
} from "./commandlineutils.js";
|
} from "./commandlineutils.js";
|
||||||
|
import { handleCommandLine } from "./commandline.js";
|
||||||
|
|
||||||
if (!process.env.NODE_ENV) {
|
if (!process.env.NODE_ENV) {
|
||||||
process.env.NODE_ENV = "production";
|
process.env.NODE_ENV = "production";
|
||||||
@ -33,80 +28,13 @@ const cli = createCliLogger(logger);
|
|||||||
export async function init(options = {}) {
|
export async function init(options = {}) {
|
||||||
const headless = options.headless ?? isHeadless;
|
const headless = options.headless ?? isHeadless;
|
||||||
cli.blank();
|
cli.blank();
|
||||||
startWaiting("Checking if Farm Control Server is running...", logger);
|
|
||||||
const isCommandLines = otpCode != undefined || isInfo == true;
|
const commandLineResult = await handleCommandLine(cli, logger);
|
||||||
let runningServer;
|
if (commandLineResult.handled) {
|
||||||
try {
|
return commandLineResult.result;
|
||||||
runningServer = await checkRunning();
|
|
||||||
await stopWaiting();
|
|
||||||
if (runningServer == false && isCommandLines == true) {
|
|
||||||
cli.failure("Farm Control Server is not running.");
|
|
||||||
cli.blank();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
await stopWaiting();
|
|
||||||
cli.failure("Failed to check if Farm Control Server is running:", err);
|
|
||||||
cli.blank();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCommandLines == true) {
|
const runningServer = commandLineResult.runningServer;
|
||||||
cli.success("Farm Control Server is running.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isInfo) {
|
|
||||||
const buildNumber =
|
|
||||||
runningServer.buildNumber ?? runningServer.build ?? "n/a";
|
|
||||||
cli.blank();
|
|
||||||
cli.sectionHeader("FarmControl Server");
|
|
||||||
cli.label(
|
|
||||||
"Version:",
|
|
||||||
runningServer.version ? `v${runningServer.version}` : "n/a",
|
|
||||||
);
|
|
||||||
cli.label("Build:", buildNumber === "dev" ? "dev" : `b${buildNumber}`);
|
|
||||||
cli.label("Authenticated:", cli.yesNo(runningServer.authenticated == true));
|
|
||||||
cli.sectionFooter();
|
|
||||||
cli.blank();
|
|
||||||
if (runningServer.authenticated == false) {
|
|
||||||
cli.sectionHeader("Authenticate");
|
|
||||||
printAuthCommand(cli);
|
|
||||||
cli.sectionFooter();
|
|
||||||
} else {
|
|
||||||
cli.sectionHeader("Host");
|
|
||||||
printerHostInfo(runningServer.host, cli);
|
|
||||||
cli.sectionFooter();
|
|
||||||
}
|
|
||||||
cli.blank();
|
|
||||||
return runningServer;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (otpCode != undefined) {
|
|
||||||
cli.blank();
|
|
||||||
startWaiting("Authenticating with OTP...", logger);
|
|
||||||
let authenticatedServer;
|
|
||||||
try {
|
|
||||||
authenticatedServer = await authenticateWithOtp(otpCode);
|
|
||||||
await stopWaiting();
|
|
||||||
} catch (err) {
|
|
||||||
await stopWaiting();
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
if (authenticatedServer.valid == false) {
|
|
||||||
cli.failure("Failed to authenticate!");
|
|
||||||
cli.failure(authenticatedServer.error);
|
|
||||||
} else {
|
|
||||||
cli.success("Authenticated with OTP.");
|
|
||||||
cli.blank();
|
|
||||||
cli.sectionHeader("Host");
|
|
||||||
printerHostInfo(authenticatedServer.host, cli);
|
|
||||||
cli.sectionFooter();
|
|
||||||
cli.blank();
|
|
||||||
return authenticatedServer;
|
|
||||||
}
|
|
||||||
cli.blank();
|
|
||||||
return authenticatedServer;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runningServer != false) {
|
if (runningServer != false) {
|
||||||
cli.warn("✘ Farm Control Server is already running.");
|
cli.warn("✘ Farm Control Server is already running.");
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
import log4js from "log4js";
|
import log4js from "log4js";
|
||||||
import { notPrompting } from "../utils.js";
|
import { notPrompting } from "../utils.js";
|
||||||
import { loadConfig } from "../config.js";
|
import { getConfigPath, loadConfig } from "../config.js";
|
||||||
import { getServerVersionInfo } from "../serverVersion.js";
|
import { getServerVersionInfo } from "../serverVersion.js";
|
||||||
import { startWaiting, stopWaiting } from "../spinner.js";
|
import { startWaiting, stopWaiting } from "../spinner.js";
|
||||||
|
|
||||||
@ -27,7 +27,10 @@ export class LocalServer {
|
|||||||
res.json({
|
res.json({
|
||||||
running: true,
|
running: true,
|
||||||
authenticated: this.socketClient.authenticated,
|
authenticated: this.socketClient.authenticated,
|
||||||
|
connected: this.socketClient.connected,
|
||||||
host: this.socketClient.host,
|
host: this.socketClient.host,
|
||||||
|
configPath: getConfigPath(),
|
||||||
|
dataDir: config.dataDir,
|
||||||
...getServerVersionInfo(),
|
...getServerVersionInfo(),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user