Merge pull request #200 from KoalaTrapLord/fix/serve-lan-client-from-backend
fix: Serve lan-client from backend at /lan (same-origin)
This commit is contained in:
3 files changed
+38
-30
No files matched your search
+10
@@ -152,8 +152,18 @@ async def health_check():
|
||||
# ── Static UI (MUST come after all @app.get routes) ──────────────────────────────────────────
|
||||
from pathlib import Path as _Path
|
||||
_legacy_ui_dir = _Path(__file__).parent / "ui"
|
||||
_lan_client_dir = _Path(__file__).parent / "lan-client"
|
||||
_precon_decks_dir = _Path(__file__).parent / "precon-decks"
|
||||
_spa_dir = _Path(__file__).parent / "frontend" / "commander-ai-lab-ui" / "dist"
|
||||
|
||||
# Mount LAN client at /lan (served before the root catch-all)
|
||||
if _lan_client_dir.exists():
|
||||
app.mount("/lan", StaticFiles(directory=str(_lan_client_dir), html=True), name="lan-client")
|
||||
|
||||
# Mount precon-decks/ so .dck files are fetchable at /precon-decks/{file}.dck
|
||||
if _precon_decks_dir.exists():
|
||||
app.mount("/precon-decks", StaticFiles(directory=str(_precon_decks_dir)), name="precon-decks")
|
||||
|
||||
if _legacy_ui_dir.exists():
|
||||
app.mount("/", StaticFiles(directory=str(_legacy_ui_dir), html=True), name="ui")
|
||||
elif _spa_dir.exists():
|
||||
|
||||
+14
-3
@@ -10,9 +10,10 @@ const AI_BRIDGE_VERSION = '1.0.0';
|
||||
// ============================================================
|
||||
|
||||
const AI_BRIDGE_CONFIG = {
|
||||
// Backend URL — defaults to localhost:8080, configurable via settings
|
||||
backendUrl: 'http://localhost:8080',
|
||||
wsUrl: 'ws://localhost:8080',
|
||||
// Backend URL — empty string = same origin (recommended when served from backend)
|
||||
// Falls back to localhost:8080 if served from a different origin
|
||||
backendUrl: '',
|
||||
wsUrl: '',
|
||||
|
||||
// Timeouts (ms)
|
||||
healthCheckTimeout: 3000,
|
||||
@@ -39,6 +40,16 @@ const AI_BRIDGE_CONFIG = {
|
||||
class BackendConnector {
|
||||
constructor(config = {}) {
|
||||
this.config = { ...AI_BRIDGE_CONFIG, ...config };
|
||||
|
||||
// Derive URLs from current page origin when empty (same-origin mode)
|
||||
if (!this.config.backendUrl) {
|
||||
this.config.backendUrl = window.location.origin; // e.g. http://localhost:8080
|
||||
}
|
||||
if (!this.config.wsUrl) {
|
||||
const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
this.config.wsUrl = `${proto}//${window.location.host}`;
|
||||
}
|
||||
|
||||
this._connected = false;
|
||||
this._modelLoaded = false;
|
||||
this._ws = null;
|
||||
|
||||
+14
-27
@@ -12723,39 +12723,26 @@ async function loadPreconForPlayer(playerIdx, preconId) {
|
||||
var player = gameState.players[playerIdx];
|
||||
if (!player) return;
|
||||
|
||||
// Try to get decklist text: embedded first, then fetch from backend .dck file
|
||||
// Try to get decklist text: embedded first, then fetch .dck from server
|
||||
var decklistText = precon.decklist || '';
|
||||
if (!decklistText && precon.fileName) {
|
||||
// Fetch .dck file from backend if available
|
||||
if (typeof AIBridge !== 'undefined' && AIBridge.connector.connected) {
|
||||
try {
|
||||
var deckData = await AIBridge.deckSource.fetchPreconDeck(precon.fileName);
|
||||
if (deckData && deckData.decklist) {
|
||||
decklistText = deckData.decklist;
|
||||
} else if (deckData && typeof deckData === 'string') {
|
||||
decklistText = deckData;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[loadPreconForPlayer] Backend deck fetch failed:', e);
|
||||
// 1. Try the API endpoint (returns JSON with decklist field)
|
||||
try {
|
||||
var apiResp = await fetch('/api/lab/precons/deck?fileName=' + encodeURIComponent(precon.fileName));
|
||||
if (apiResp.ok) {
|
||||
var deckData = await apiResp.json();
|
||||
if (deckData && deckData.decklist) decklistText = deckData.decklist;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[loadPreconForPlayer] API deck fetch failed:', e);
|
||||
}
|
||||
// Fallback: try to fetch .dck file directly from precon-decks/ (same origin)
|
||||
// 2. Fallback: fetch .dck file directly from static mount
|
||||
if (!decklistText) {
|
||||
try {
|
||||
var resp = await fetch('precon-decks/' + precon.fileName);
|
||||
if (resp.ok) {
|
||||
decklistText = await resp.text();
|
||||
}
|
||||
} catch (e) {
|
||||
// Fallback: try relative to backend
|
||||
try {
|
||||
var resp2 = await fetch('/precon-decks/' + precon.fileName);
|
||||
if (resp2.ok) {
|
||||
decklistText = await resp2.text();
|
||||
}
|
||||
} catch (e2) {
|
||||
console.warn('[loadPreconForPlayer] Could not fetch .dck file:', precon.fileName);
|
||||
}
|
||||
var staticResp = await fetch('/precon-decks/' + encodeURIComponent(precon.fileName));
|
||||
if (staticResp.ok) decklistText = await staticResp.text();
|
||||
} catch (e2) {
|
||||
console.warn('[loadPreconForPlayer] Static .dck fetch failed:', precon.fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user