Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified release/GameNet_Agent.exe
Binary file not shown.
17 changes: 10 additions & 7 deletions release/config/config/apps.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
{
"apps": [
{ "id": "notepad", "name": "Notepad", "path": "C:\\Windows\\System32\\notepad.exe", "args": [] },
{ "id": "calc", "name": "Calculator", "path": "C:\\Windows\\System32\\calc.exe", "args": [] },
{ "id": "mspaint", "name": "Paint", "path": "C:\\Windows\\System32\\mspaint.exe", "args": [] }
]
}
[
{
"name": "VLC Player",
"path": "C:\\Program Files\\VideoLAN\\VLC\\vlc.exe"
},
{
"name": "Notepad",
"path": "C:\\Windows\\System32\\notepad.exe"
}
]
1 change: 1 addition & 0 deletions server.pid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

7 changes: 7 additions & 0 deletions windows-launcher-agent/config.bak/apps.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"apps": [
{ "id": "notepad", "name": "Notepad", "path": "C:\\Windows\\System32\\notepad.exe", "args": [] },
{ "id": "calc", "name": "Calculator", "path": "C:\\Windows\\System32\\calc.exe", "args": [] },
{ "id": "mspaint", "name": "Paint", "path": "C:\\Windows\\System32\\mspaint.exe", "args": [] }
]
}
10 changes: 10 additions & 0 deletions windows-launcher-agent/config.bak/config/apps.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"name": "VLC Player",
"path": "C:\\Program Files\\VideoLAN\\VLC\\vlc.exe"
},
{
"name": "Notepad",
"path": "C:\\Windows\\System32\\notepad.exe"
}
]
17 changes: 10 additions & 7 deletions windows-launcher-agent/config/apps.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
{
"apps": [
{ "id": "notepad", "name": "Notepad", "path": "C:\\Windows\\System32\\notepad.exe", "args": [] },
{ "id": "calc", "name": "Calculator", "path": "C:\\Windows\\System32\\calc.exe", "args": [] },
{ "id": "mspaint", "name": "Paint", "path": "C:\\Windows\\System32\\mspaint.exe", "args": [] }
]
}
[
{
"name": "VLC Player",
"path": "C:\\Program Files\\VideoLAN\\VLC\\vlc.exe"
},
{
"name": "Notepad",
"path": "C:\\Windows\\System32\\notepad.exe"
}
]
10 changes: 10 additions & 0 deletions windows-launcher-agent/custom/apps.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"name": "VLC Player",
"path": "C:\\Program Files\\VideoLAN\\VLC\\vlc.exe"
},
{
"name": "Notepad",
"path": "C:\\Windows\\System32\\notepad.exe"
}
]
9 changes: 7 additions & 2 deletions windows-launcher-agent/logs/agent.log
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
[2025-08-11T00:18:48.317Z] [INFO] Loaded 3 apps from config
[2025-08-11T00:18:48.323Z] [INFO] Windows Launcher Agent listening at http://127.0.0.1:5000
[2025-08-11T12:46:40.112Z] [WARN] apps.json not found at /workspace/windows-launcher-agent/custom/apps.json. A default config has been created there. Please update it with your applications.
[2025-08-11T12:46:40.112Z] [INFO] Loaded 2 apps from config (/workspace/windows-launcher-agent/custom/apps.json)
[2025-08-11T12:46:40.118Z] [INFO] Windows Launcher Agent listening at http://127.0.0.1:5056
[2025-08-11T12:46:41.112Z] [ERROR] Invalid JSON in apps config (/workspace/windows-launcher-agent/custom/apps.json): Expected property name or '}' in JSON at position 2 (line 1 column 3)
[2025-08-11T12:46:41.112Z] [WARN] apps.json not found at /workspace/windows-launcher-agent/custom/apps.json. A default config has been created there. Please update it with your applications.
[2025-08-11T12:46:41.113Z] [INFO] Loaded 2 apps from config (/workspace/windows-launcher-agent/custom/apps.json)
[2025-08-11T12:46:41.118Z] [INFO] Windows Launcher Agent listening at http://127.0.0.1:5057
5 changes: 5 additions & 0 deletions windows-launcher-agent/server.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[dotenv@17.2.1] injecting env (0) from .env -- tip: 🔐 encrypt with Dotenvx: https://dotenvx.com
[2025-08-11T12:46:41.112Z] [ERROR] Invalid JSON in apps config (/workspace/windows-launcher-agent/custom/apps.json): Expected property name or '}' in JSON at position 2 (line 1 column 3)
[2025-08-11T12:46:41.112Z] [WARN] apps.json not found at /workspace/windows-launcher-agent/custom/apps.json. A default config has been created there. Please update it with your applications.
[2025-08-11T12:46:41.113Z] [INFO] Loaded 2 apps from config (/workspace/windows-launcher-agent/custom/apps.json)
[2025-08-11T12:46:41.118Z] [INFO] Windows Launcher Agent listening at http://127.0.0.1:5057
119 changes: 112 additions & 7 deletions windows-launcher-agent/src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function writeLogLine(level, message) {
}

function logInfo(msg) { writeLogLine('INFO', msg); }
function logWarn(msg) { writeLogLine('WARN', msg); }
function logError(msg) { writeLogLine('ERROR', msg); }

const host = process.env.HOST || '127.0.0.1';
Expand Down Expand Up @@ -73,20 +74,124 @@ app.use((req, res, next) => {
next();
});

const appsConfigPath = path.join(appRoot, 'config', 'apps.json');
// Resolve apps.json path (env override or default next to executable)
const envConfigPath = process.env.APP_CONFIG_PATH && String(process.env.APP_CONFIG_PATH).trim() !== ''
? path.resolve(process.env.APP_CONFIG_PATH)
: '';
const defaultAppsConfigPath = path.join(appRoot, 'config', 'apps.json');
const appsConfigPath = envConfigPath || defaultAppsConfigPath;

let apps = [];

function getDefaultConfigArray() {
return [
{
name: 'VLC Player',
path: 'C:\\Program Files\\VideoLAN\\VLC\\vlc.exe',
},
{
name: 'Notepad',
path: 'C:\\Windows\\System32\\notepad.exe',
},
];
}

function writeDefaultConfig(targetPath, isDefaultLocation) {
try {
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
} catch (_) {}
const defaultArray = getDefaultConfigArray();
const json = JSON.stringify(defaultArray, null, 2);
try {
fs.writeFileSync(targetPath, json, 'utf8');
} catch (e) {
logError(`Failed to write default apps.json at ${targetPath}: ${e.message}`);
return;
}
if (isDefaultLocation) {
// Required exact warning message for default location
logWarn('apps.json not found. A default config has been created in ./config/apps.json. Please update it with your applications.');
} else {
logWarn(`apps.json not found at ${targetPath}. A default config has been created there. Please update it with your applications.`);
}
}

function slugifyNameToId(name, existingIds) {
const base = String(name || '').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') || 'app';
let candidate = base;
let counter = 2;
while (existingIds.has(candidate)) {
candidate = `${base}-${counter++}`;
}
existingIds.add(candidate);
return candidate;
}

function normalizeApps(rawList) {
const existingIds = new Set();
const normalized = [];
for (const entry of rawList) {
if (!entry || typeof entry !== 'object') continue;
const name = String(entry.name || '').trim();
const exePath = String(entry.path || '').trim();
if (!name || !exePath) continue;
let id = typeof entry.id === 'string' && entry.id.trim() ? entry.id.trim() : '';
if (!id) {
id = slugifyNameToId(name, existingIds);
} else if (existingIds.has(id)) {
id = slugifyNameToId(`${name}-${id}`, existingIds);
} else {
existingIds.add(id);
}
const args = Array.isArray(entry.args) ? entry.args.filter((a) => typeof a === 'string') : [];
normalized.push({ id, name, path: exePath, args });
}
return normalized;
}

function loadAppsConfig() {
const isDefaultLocation = appsConfigPath === defaultAppsConfigPath;

// Create default if missing
try {
if (!fs.existsSync(appsConfigPath)) {
writeDefaultConfig(appsConfigPath, isDefaultLocation);
}
} catch (_) {}

// Load and parse
try {
const raw = fs.readFileSync(appsConfigPath, 'utf8');
const parsed = JSON.parse(raw);
if (!parsed || !Array.isArray(parsed.apps)) {
throw new Error('Invalid apps config format');
let parsed;
try {
parsed = JSON.parse(raw);
} catch (e) {
logError(`Invalid JSON in apps config (${appsConfigPath}): ${e.message}`);
writeDefaultConfig(appsConfigPath, isDefaultLocation);
parsed = getDefaultConfigArray();
}

let list;
if (Array.isArray(parsed)) {
list = parsed;
} else if (parsed && Array.isArray(parsed.apps)) {
list = parsed.apps;
} else {
logError(`Invalid apps config format in ${appsConfigPath}. Replacing with default.`);
writeDefaultConfig(appsConfigPath, isDefaultLocation);
list = getDefaultConfigArray();
}
apps = parsed.apps;
logInfo(`Loaded ${apps.length} apps from config`);

apps = normalizeApps(list);
logInfo(`Loaded ${apps.length} apps from config (${appsConfigPath})`);
} catch (err) {
logError(`Failed to load apps config: ${err.message}`);
apps = [];
// Ensure we still have at least defaults in memory
try {
apps = normalizeApps(getDefaultConfigArray());
} catch (_) {
apps = [];
}
}
}
loadAppsConfig();
Expand Down