fix : btid, login without docker

This commit is contained in:
karthik 2025-09-20 17:34:38 +05:30
parent 389ffe6555
commit c7a9f1fcf2
7 changed files with 253 additions and 144 deletions

View File

@ -8,6 +8,7 @@ let currentSharedData = null; // Store latest data for initial sync
let currentSelectedVenue = 'Select Venue';
let currentSelectedRace = 1;
let currentStopMessage = '';
let currentBtid = null; // Store in-memory BTID
function createWindows() {
const displays = screen.getAllDisplays();
@ -42,6 +43,9 @@ function createWindows() {
screenWindow.loadURL('http://10.150.40.124:4200/shared-display');
// Debugging: Open DevTools for second screen to verify logs
// screenWindow.webContents.openDevTools({ mode: 'detach' });
// Handle opening second screen and send initial data
ipcMain.on('open-second-screen', () => {
screenWindow.show();
@ -52,6 +56,7 @@ function createWindows() {
screenWindow.webContents.send('update-selected-venue', currentSelectedVenue);
screenWindow.webContents.send('update-selected-race', currentSelectedRace);
screenWindow.webContents.send('update-stop-message', currentStopMessage);
screenWindow.webContents.send('update-btid', currentBtid);
}
});
@ -81,7 +86,7 @@ function createWindows() {
}
});
// Add this new handler
// Handle stop message sync
ipcMain.on('sync-stop-message', (event, message) => {
currentStopMessage = message;
if (screenWindow && screenWindow.webContents) {
@ -89,7 +94,16 @@ function createWindows() {
}
});
// Handle BTID request
// Handle BTID sync
ipcMain.on('sync-btid', (event, btid) => {
console.log('[MAIN] sync-btid received:', btid);
currentBtid = btid; // Store in-memory BTID
if (screenWindow && screenWindow.webContents) {
screenWindow.webContents.send('update-btid', btid);
}
});
// Handle BTID request from file
ipcMain.handle('get-btid', () => {
try {
const filePath = path.join(process.env.HOME || process.env.USERPROFILE, 'BTID', 'betting.txt');
@ -97,10 +111,16 @@ function createWindows() {
const match = content.match(/Btid\s*=\s*(\d+)/i);
return match ? match[1] : null;
} catch (err) {
console.error('Error reading betting.txt:', err);
console.error('[MAIN] Error reading betting.txt:', err);
return null;
}
});
// Allow renderers to request current in-memory BTID on demand
ipcMain.handle('request-current-btid', async () => {
console.log('[MAIN] request-current-btid =>', currentBtid);
return currentBtid || null;
});
}
app.whenReady().then(createWindows);

View File

@ -4,13 +4,15 @@ contextBridge.exposeInMainWorld('electronAPI', {
openSecondScreen: () => ipcRenderer.send('open-second-screen'),
closeSecondScreen: () => ipcRenderer.send('close-second-screen'),
getBtid: () => ipcRenderer.invoke('get-btid'),
getCurrentBtid: () => ipcRenderer.invoke('request-current-btid'), // NEW: Request in-memory BTID
syncSharedData: (data) => ipcRenderer.send('sync-shared-data', data),
onUpdateSharedData: (callback) => ipcRenderer.on('update-shared-data', (event, data) => callback(data)),
// Add these new lines
syncStopMessage: (message) => ipcRenderer.send('sync-stop-message', message),
onUpdateStopMessage: (callback) => ipcRenderer.on('update-stop-message', (event, message) => callback(message)),
syncSelectedVenue: (venue) => ipcRenderer.send('sync-selected-venue', venue),
onUpdateSelectedVenue: (callback) => ipcRenderer.on('update-selected-venue', (event, venue) => callback(venue)),
syncSelectedRace: (race) => ipcRenderer.send('sync-selected-race', race),
onUpdateSelectedRace: (callback) => ipcRenderer.on('update-selected-race', (event, race) => callback(race)),
syncBtid: (btid) => ipcRenderer.send('sync-btid', btid), // NEW: Send BTID to main
onUpdateBtid: (callback) => ipcRenderer.on('update-btid', (event, btid) => callback(btid)), // NEW: Listen for BTID updates
});

View File

@ -1,4 +1,4 @@
// shared-display.component.ts
// shared-display.component.ts (updated ngOnInit to read initial values from localStorage)
import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedStateService } from '../../service/shared-state.service';
@ -13,7 +13,6 @@ interface SharedData {
salesTotal: number;
receiveTotal: number;
totalClicks: number;
}
@Component({
@ -51,11 +50,66 @@ export class SharedDisplayComponent implements OnInit {
) {}
ngOnInit(): void {
console.log('[SHARED DISPLAY] Initializing, electronAPI available:', !!window.electronAPI);
this.btid = localStorage.getItem('btid');
console.log('[SHARED DISPLAY] Initializing, electronAPI available:', !!(window as any).electronAPI);
// NEW: Read initial values from localStorage (set by login)
this.btid = localStorage.getItem('btid') || null;
this.selectedVenue = localStorage.getItem('selectedVenue') || this.selectedVenue;
this.selectedRace = localStorage.getItem('selectedRace') || this.selectedRace;
console.log('[SHARED DISPLAY] Initial values from localStorage:', { btid: this.btid, selectedVenue: this.selectedVenue, selectedRace: this.selectedRace });
const electronAPI = (window as any).electronAPI;
if (electronAPI) {
if (!electronAPI) {
console.error('[SHARED DISPLAY] electronAPI not available');
return;
}
// 1) Ask main process for the current in-memory BTID (avoid race)
if (electronAPI.getCurrentBtid) {
try {
electronAPI.getCurrentBtid().then((btidFromMain: string | null) => {
console.log('[SHARED DISPLAY] getCurrentBtid returned:', btidFromMain);
if (btidFromMain) {
this.btid = btidFromMain;
try { localStorage.setItem('btid', btidFromMain); } catch (e) { /* ignore */ }
this.cdRef.detectChanges();
}
}).catch((err: any) => {
console.warn('[SHARED DISPLAY] getCurrentBtid failed:', err);
});
} catch (err) {
console.warn('[SHARED DISPLAY] getCurrentBtid exception:', err);
}
} else if (electronAPI.getBtid) {
// Fallback to existing getBtid (reads file via main handler)
electronAPI.getBtid().then((btidFromFile: string | null) => {
console.log('[SHARED DISPLAY] getBtid returned:', btidFromFile);
if (btidFromFile) {
this.btid = btidFromFile;
try { localStorage.setItem('btid', btidFromFile); } catch (e) { /* ignore */ }
this.cdRef.detectChanges();
}
}).catch((err: any) => {
console.warn('[SHARED DISPLAY] getBtid failed:', err);
});
}
// 2) Listen for update-btid events (handles later syncs)
if (electronAPI.onUpdateBtid) {
electronAPI.onUpdateBtid((btid: string) => {
console.log('[SHARED DISPLAY] Received update-btid:', btid);
if (btid) {
this.btid = btid;
try { localStorage.setItem('btid', btid); } catch (e) { /* ignore */ }
this.cdRef.detectChanges();
}
});
} else {
console.warn('[SHARED DISPLAY] onUpdateBtid not available');
}
// Existing shared-data / venue / race listeners
if (electronAPI.onUpdateSharedData) {
electronAPI.onUpdateSharedData((data: SharedData) => {
console.log('[SHARED DISPLAY] Received IPC data:', data);
if (!data) return;
@ -68,20 +122,32 @@ export class SharedDisplayComponent implements OnInit {
console.log('[SHARED DISPLAY] Updated filledRows:', this.filledRows.map(row => ({ ...row, numbers: JSON.stringify(row.numbers) })));
this.cdRef.detectChanges();
});
}
if (electronAPI.onUpdateSelectedVenue) {
electronAPI.onUpdateSelectedVenue((venue: string) => {
this.selectedVenue = venue;
console.log('[SHARED DISPLAY] Venue updated via IPC to:', this.selectedVenue);
try { localStorage.setItem('selectedVenue', venue); } catch (e) { /* ignore */ }
this.cdRef.detectChanges();
});
}
if (electronAPI.onUpdateSelectedRace) {
electronAPI.onUpdateSelectedRace((race: number) => {
this.selectedRace = race.toString();
console.log('[SHARED DISPLAY] Race updated via IPC to:', this.selectedRace);
try { localStorage.setItem('selectedRace', race.toString()); } catch (e) { /* ignore */ }
this.cdRef.detectChanges();
});
}
if (electronAPI.onUpdateStopMessage) {
electronAPI.onUpdateStopMessage((msg: string) => {
console.log('[SHARED DISPLAY] Stop message received:', msg);
// Optionally handle display of stop message
this.cdRef.detectChanges();
});
} else {
console.error('[SHARED DISPLAY] electronAPI not available');
}
}
}

View File

@ -168,7 +168,7 @@ div[style*="background-color: black"] .custom-cell {
overflow: hidden;
box-sizing: border-box;
animation: scroll 20s linear infinite; /* Adjust duration for speed */
width: 55%; /* Ensure it takes full width */
width: 100%; /* Ensure it takes full width */
}
@keyframes scroll {

View File

@ -220,137 +220,156 @@ export class LoginComponent implements OnInit, OnDestroy {
* Will fail if BTID cannot be fetched from Electron API
*/
async onSubmit(): Promise<void> {
// validate form
if (this.loginForm.invalid) {
this.loginForm.markAllAsTouched();
return;
}
this.loginError = null;
this.passwordStatus = true;
const email = (this.loginForm.get('email')!.value || '').toString().trim();
const password = (this.loginForm.get('password')!.value || '').toString();
// ✅ CRITICAL: Load BTID FIRST - This will throw if fails
let fetchedBtid: string;
try {
console.log('🔄 Fetching BTID from Electron API...');
await this.btcService.loadBtid();
fetchedBtid = this.btcService.btid!;
if (!fetchedBtid) {
throw new Error('BTID is null after fetch');
}
console.log('✅ BTID successfully fetched:', fetchedBtid);
} catch (btidError: any) {
console.error('❌ BTID fetch failed:', btidError);
this.loginError = `Failed to load BTID: ${btidError.message}. Please check Electron connection and try again.`;
this.passwordStatus = false;
return; // STOP LOGIN - No fallback allowed
}
// ✅ Build payload with REAL BTID - NO FALLBACK
const payload = {
opCard: email,
password: password,
btId: fetchedBtid, // Real BTID only
usrId: '',
btMake: 0,
};
console.log('📦 Login payload being sent:', payload);
try {
// 1) POST to login endpoint
const loginUrl = 'http://localhost:8080/login';
const loginResp: any = await lastValueFrom(
this.http.post(loginUrl, payload, { observe: 'body' })
);
console.log('🧠 Login response:', loginResp);
// Store response safely
try {
localStorage.setItem('loginRes', JSON.stringify(loginResp));
console.log('✅ Full login response saved');
} catch (e) {
console.error('❌ Failed to stringify login response:', e);
localStorage.setItem('loginRes', JSON.stringify(loginResp, Object.getOwnPropertyNames(loginResp)));
}
// Parse username from response
const rawLoginRes = localStorage.getItem('loginRes');
if (rawLoginRes) {
try {
const parsed = JSON.parse(rawLoginRes);
const username = parsed?.log?.cUsrNm || 'Unknown User';
console.log('🧑 Username from loginRes:', username);
localStorage.setItem('userName', username);
} catch (e) {
console.error('❌ Failed to parse loginRes from localStorage', e);
}
}
// ✅ Save REAL BTID to localStorage for second screen
localStorage.setItem('btid', fetchedBtid);
console.log('💾 BTID saved to localStorage:', fetchedBtid);
// Prepare print payload
const printData = {
name: localStorage.getItem('userName') || 'Unknown User',
employeeId: email, // Use email as employee ID
action: 'login',
type: 'login',
};
// 2) Print (commented out - uncomment if needed)
/*
const printRes = await fetch('http://localhost:9100/print', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(printData),
});
if (!printRes.ok) {
throw new Error(`Print failed (${printRes.status})`);
}
console.log('🖨️ Print successful');
*/
// 3) Fetch race card with DYNAMIC values - NO FALLBACKS
console.log('🔄 Fetching race card with:', { opCard: email, password, btId: fetchedBtid });
const rpInfo = await lastValueFrom(
this.btcService.fetchRaceCard(email, password, fetchedBtid) // Dynamic opCard, real BTID
);
console.log('📦 Race Card fetched successfully:', rpInfo);
localStorage.setItem('rpinfo', JSON.stringify(rpInfo));
// 4) Navigate to second screen
console.log('🚀 Navigating to home with BTID:', fetchedBtid);
(window as any).electronAPI?.openSecondScreen?.();
this.router.navigate(['/home']);
} catch (err: any) {
console.error('❌ Login flow failed:', err);
// Specific error handling
if (err?.message?.includes('Print failed')) {
this.loginError = 'Login failed: printing service unavailable.';
} else if (err?.status === 401 || err?.status === 400) {
this.loginError = 'Invalid login credentials';
} else if (err?.message?.includes('BTID')) {
this.loginError = `BTID Error: ${err.message}`;
} else {
this.loginError = err?.message || 'Login failed. Please try again.';
}
this.passwordStatus = false;
}
// validate form
if (this.loginForm.invalid) {
this.loginForm.markAllAsTouched();
return;
}
this.loginError = null;
this.passwordStatus = true;
const email = (this.loginForm.get('email')!.value || '').toString().trim();
const password = (this.loginForm.get('password')!.value || '').toString();
// ✅ CRITICAL: Load BTID FIRST - This will throw if fails
let fetchedBtid: string;
try {
console.log('🔄 Fetching BTID from Electron API...');
await this.btcService.loadBtid();
fetchedBtid = this.btcService.btid!;
if (!fetchedBtid) {
throw new Error('BTID is null after fetch');
}
console.log('✅ BTID successfully fetched:', fetchedBtid);
} catch (btidError: any) {
console.error('❌ BTID fetch failed:', btidError);
this.loginError = `Failed to load BTID: ${btidError.message}. Please check Electron connection and try again.`;
this.passwordStatus = false;
return; // STOP LOGIN - No fallback allowed
}
// ✅ Build payload with REAL BTID - NO FALLBACK
const payload = {
opCard: email,
password: password,
btId: fetchedBtid, // Real BTID only
usrId: '',
btMake: 0,
};
console.log('📦 Login payload being sent:', payload);
try {
// 1) POST to login endpoint
const loginUrl = 'http://localhost:8080/login';
const loginResp: any = await lastValueFrom(
this.http.post(loginUrl, payload, { observe: 'body' })
);
console.log('🧠 Login response:', loginResp);
// Store response safely
try {
localStorage.setItem('loginRes', JSON.stringify(loginResp));
console.log('✅ Full login response saved');
} catch (e) {
console.error('❌ Failed to stringify login response:', e);
localStorage.setItem('loginRes', JSON.stringify(loginResp, Object.getOwnPropertyNames(loginResp)));
}
// Parse username from response
const rawLoginRes = localStorage.getItem('loginRes');
if (rawLoginRes) {
try {
const parsed = JSON.parse(rawLoginRes);
const username = parsed?.log?.cUsrNm || 'Unknown User';
console.log('🧑 Username from loginRes:', username);
localStorage.setItem('userName', username);
} catch (e) {
console.error('❌ Failed to parse loginRes from localStorage', e);
}
}
// ✅ Save REAL BTID to localStorage for second screen
localStorage.setItem('btid', fetchedBtid);
console.log('💾 BTID saved to localStorage:', fetchedBtid);
// NEW: Sync BTID to main process for immediate second screen access via getCurrentBtid
if ((window as any).electronAPI?.syncBtid) {
(window as any).electronAPI.syncBtid(fetchedBtid);
console.log('📡 BTID synced to main process via IPC');
}
// Prepare print payload
const printData = {
name: localStorage.getItem('userName') || 'Unknown User',
employeeId: email, // Use email as employee ID
action: 'login',
type: 'login',
};
// 2) Print (commented out - uncomment if needed)
/*
const printRes = await fetch('http://localhost:9100/print', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(printData),
});
if (!printRes.ok) {
throw new Error(`Print failed (${printRes.status})`);
}
console.log('🖨️ Print successful');
*/
// 3) Fetch race card with DYNAMIC values - NO FALLBACKS
console.log('🔄 Fetching race card with:', { opCard: email, password, btId: fetchedBtid });
const rpInfo = await lastValueFrom(
this.btcService.fetchRaceCard(email, password, fetchedBtid) // Dynamic opCard, real BTID
);
console.log('📦 Race Card fetched successfully:', rpInfo);
localStorage.setItem('rpinfo', JSON.stringify(rpInfo));
// NEW: Set initial race from rpInfo to localStorage for second screen initial display
// Adjust these extractions based on the actual structure of rpInfo (e.g., rpInfo.currentRace)
const initialRace = rpInfo.race || rpInfo.currentRace || 1; // Example: Adjust path to your rpInfo structure
localStorage.setItem('selectedRace', initialRace.toString());
console.log('💾 Initial race saved to localStorage:', { initialRace });
// NEW: Sync initial race to main process (for currentSelectedRace in main.js)
if ((window as any).electronAPI) {
if ((window as any).electronAPI.syncSelectedRace) {
(window as any).electronAPI.syncSelectedRace(initialRace);
console.log('📡 Initial race synced to main process via IPC');
}
}
// 4) Navigate to second screen
console.log('🚀 Navigating to home with BTID:', fetchedBtid);
(window as any).electronAPI?.openSecondScreen?.();
this.router.navigate(['/home']);
} catch (err: any) {
console.error('❌ Login flow failed:', err);
// Specific error handling
if (err?.message?.includes('Print failed')) {
this.loginError = 'Login failed: printing service unavailable.';
} else if (err?.status === 401 || err?.status === 400) {
this.loginError = 'Invalid login credentials';
} else if (err?.message?.includes('BTID')) {
this.loginError = `BTID Error: ${err.message}`;
} else {
this.loginError = err?.message || 'Login failed. Please try again.';
}
this.passwordStatus = false;
}
}
showConfirmModal: boolean = false;
confirmShutdown(): void {

View File

@ -169,7 +169,7 @@ export class StopbetService implements OnDestroy {
}
this.http
.get(`http://localhost:8080/stopbet/raw?venue=${this.currentVenue}&date=${this.currentDate}`)
.get(`http://localhost:8089/stopbet/raw?venue=${this.currentVenue}&date=${this.currentDate}`)
.subscribe({
next: (res: any) => {
if (res && res.ok && res.data) {
@ -205,7 +205,7 @@ export class StopbetService implements OnDestroy {
}
try {
this.eventSource = new EventSource('http://localhost:8080/stopbet/stream');
this.eventSource = new EventSource('http://localhost:8089/stopbet/stream');
} catch (err) {
console.error('[STOPBET] Failed to create EventSource:', err);
return;

View File

@ -2,15 +2,17 @@ interface ElectronAPI {
openSecondScreen: () => void;
closeSecondScreen: () => void;
getBtid: () => Promise<string | null>;
getCurrentBtid: () => Promise<string | null>; // NEW: Request in-memory BTID
syncSharedData: (data: SharedData) => void;
onUpdateSharedData: (callback: (data: SharedData) => void) => void;
// Add these new lines
syncStopMessage: (message: string) => void;
onUpdateStopMessage: (callback: (message: string) => void) => void;
syncSelectedVenue: (venue: string) => void;
onUpdateSelectedVenue: (callback: (venue: string) => void) => void;
syncSelectedRace: (race: number) => void;
onUpdateSelectedRace: (callback: (race: number) => void) => void;
syncBtid: (btid: string) => void; // NEW: Send BTID to main
onUpdateBtid: (callback: (btid: string) => void) => void; // NEW: Listen for BTID updates
}
interface SharedData {