Änderungen: - Implementierung des neuen Routers für TaxiHighscore zur Verwaltung von Highscore-Daten. - Anpassung der Datenbankmodelle zur Unterstützung von TaxiHighscore-Associations. - Erweiterung der Vue-Komponenten zur Anzeige und Speicherung von Highscores im Taxi-Spiel. - Verbesserung der Statusanzeige im AppHeader zur besseren Benutzerinteraktion. Diese Anpassungen erweitern die Spielmechanik und Benutzererfahrung, indem sie die Verwaltung von Highscores integrieren und die Benutzeroberfläche optimieren.
359 lines
12 KiB
JavaScript
359 lines
12 KiB
JavaScript
import { createStore } from 'vuex';
|
|
import dialogs from './modules/dialogs';
|
|
import loadMenu from '../utils/menuLoader.js';
|
|
import router from '../router';
|
|
import apiClient from '../utils/axios.js';
|
|
import { io } from 'socket.io-client';
|
|
|
|
const store = createStore({
|
|
state: {
|
|
isLoggedIn: localStorage.getItem('isLoggedIn') === 'true',
|
|
connectionStatus: 'disconnected', // 'connected', 'connecting', 'disconnected', 'error'
|
|
daemonConnectionStatus: 'disconnected', // 'connected', 'connecting', 'disconnected', 'error'
|
|
user: JSON.parse(localStorage.getItem('user')) || null,
|
|
language: (() => {
|
|
// Verwende die gleiche Logik wie in main.js
|
|
const browserLanguage = navigator.language || navigator.languages[0];
|
|
const germanSpeakingCountries = ['de', 'at', 'ch', 'li'];
|
|
|
|
if (browserLanguage.startsWith('de')) {
|
|
return 'de';
|
|
}
|
|
|
|
const allLanguages = navigator.languages || [navigator.language];
|
|
for (const lang of allLanguages) {
|
|
if (lang.startsWith('de-')) {
|
|
const countryCode = lang.split('-')[1]?.toLowerCase();
|
|
if (germanSpeakingCountries.includes(countryCode)) {
|
|
return 'de';
|
|
}
|
|
}
|
|
if (lang.startsWith('de_')) {
|
|
const countryCode = lang.split('_')[1]?.toLowerCase();
|
|
if (germanSpeakingCountries.includes(countryCode)) {
|
|
return 'de';
|
|
}
|
|
}
|
|
}
|
|
|
|
return 'en';
|
|
})(),
|
|
menu: JSON.parse(localStorage.getItem('menu')) || [],
|
|
socket: null,
|
|
daemonSocket: null,
|
|
menuNeedsUpdate: false,
|
|
},
|
|
mutations: {
|
|
async dologin(state, user) {
|
|
state.isLoggedIn = true;
|
|
state.user = user;
|
|
localStorage.setItem('isLoggedIn', 'true');
|
|
localStorage.setItem('user', JSON.stringify(user));
|
|
state.menuNeedsUpdate = true;
|
|
if (user.param.filter(param => ['birthdate', 'gender'].includes(param.name)).length < 2) {
|
|
router.push({ path: '/settings/personal' });
|
|
}
|
|
},
|
|
async dologout(state) {
|
|
state.isLoggedIn = false;
|
|
state.user = null;
|
|
localStorage.removeItem('isLoggedIn');
|
|
localStorage.removeItem('user');
|
|
localStorage.removeItem('menu');
|
|
state.menuNeedsUpdate = false;
|
|
|
|
// Setze die Sprache auf die Browser-Sprache zurück
|
|
const browserLanguage = navigator.language || navigator.languages[0];
|
|
const germanSpeakingCountries = ['de', 'at', 'ch', 'li'];
|
|
|
|
if (browserLanguage.startsWith('de')) {
|
|
state.language = 'de';
|
|
} else {
|
|
const allLanguages = navigator.languages || [navigator.language];
|
|
let isGerman = false;
|
|
for (const lang of allLanguages) {
|
|
if (lang.startsWith('de-')) {
|
|
const countryCode = lang.split('-')[1]?.toLowerCase();
|
|
if (germanSpeakingCountries.includes(countryCode)) {
|
|
isGerman = true;
|
|
break;
|
|
}
|
|
}
|
|
if (lang.startsWith('de_')) {
|
|
const countryCode = lang.split('_')[1]?.toLowerCase();
|
|
if (germanSpeakingCountries.includes(countryCode)) {
|
|
isGerman = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
state.language = isGerman ? 'de' : 'en';
|
|
}
|
|
},
|
|
setLanguage(state, language) {
|
|
state.language = language;
|
|
},
|
|
setMenu(state, menu) {
|
|
state.menu = menu;
|
|
localStorage.setItem('menu', JSON.stringify(menu));
|
|
state.menuNeedsUpdate = false;
|
|
},
|
|
setSocket(state, socket) {
|
|
state.socket = socket;
|
|
},
|
|
setConnectionStatus(state, status) {
|
|
state.connectionStatus = status;
|
|
},
|
|
setDaemonConnectionStatus(state, status) {
|
|
state.daemonConnectionStatus = status;
|
|
},
|
|
clearSocket(state) {
|
|
if (state.socket) {
|
|
state.socket.disconnect();
|
|
}
|
|
state.socket = null;
|
|
},
|
|
setDaemonSocket(state, daemonSocket) {
|
|
state.daemonSocket = daemonSocket;
|
|
},
|
|
clearDaemonSocket(state) {
|
|
if (state.daemonSocket) {
|
|
state.daemonSocket.close();
|
|
}
|
|
state.daemonSocket = null;
|
|
state.daemonConnectionStatus = 'disconnected';
|
|
},
|
|
},
|
|
actions: {
|
|
async login({ commit, dispatch }, user) {
|
|
await commit('dologin', user);
|
|
await dispatch('initializeSocket');
|
|
await dispatch('initializeDaemonSocket');
|
|
const socket = this.getters.socket;
|
|
if (socket) {
|
|
const idForSocket = user?.hashedId || user?.id;
|
|
if (idForSocket) socket.emit('setUserId', idForSocket);
|
|
}
|
|
await dispatch('loadMenu');
|
|
},
|
|
logout({ commit }) {
|
|
commit('clearSocket');
|
|
commit('clearDaemonSocket');
|
|
commit('dologout');
|
|
router.push('/');
|
|
},
|
|
initializeSocket({ commit, state }) {
|
|
if (state.isLoggedIn && state.user) {
|
|
let currentSocket = state.socket;
|
|
const connectSocket = () => {
|
|
if (currentSocket) {
|
|
currentSocket.disconnect();
|
|
}
|
|
commit('setConnectionStatus', 'connecting');
|
|
// Socket.io URL für lokale Entwicklung und Produktion
|
|
let socketIoUrl = import.meta.env.VITE_SOCKET_IO_URL || import.meta.env.VITE_API_BASE_URL;
|
|
|
|
// Für lokale Entwicklung: direkte Backend-Verbindung
|
|
if (!socketIoUrl && (import.meta.env.DEV || window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1')) {
|
|
socketIoUrl = 'http://localhost:3001';
|
|
}
|
|
|
|
const socket = io(socketIoUrl, {
|
|
secure: true,
|
|
transports: ['websocket', 'polling']
|
|
});
|
|
|
|
socket.on('connect', () => {
|
|
retryCount = 0; // Reset retry counter on successful connection
|
|
commit('setConnectionStatus', 'connected');
|
|
const idForSocket = state.user?.hashedId || state.user?.id;
|
|
if (idForSocket) socket.emit('setUserId', idForSocket);
|
|
});
|
|
|
|
socket.on('disconnect', (reason) => {
|
|
commit('setConnectionStatus', 'disconnected');
|
|
retryConnection(connectSocket);
|
|
});
|
|
|
|
socket.on('connect_error', (error) => {
|
|
commit('setConnectionStatus', 'error');
|
|
});
|
|
|
|
commit('setSocket', socket);
|
|
};
|
|
|
|
let retryCount = 0;
|
|
const maxRetries = 10;
|
|
const retryConnection = (reconnectFn) => {
|
|
console.log(`Reconnect-Versuch ${retryCount + 1}/${maxRetries}`);
|
|
if (retryCount >= maxRetries) {
|
|
// Nach maxRetries alle 5 Sekunden weiter versuchen
|
|
console.log('Max Retries erreicht, versuche weiter alle 5 Sekunden...');
|
|
setTimeout(() => {
|
|
reconnectFn();
|
|
}, 5000);
|
|
return;
|
|
}
|
|
retryCount++;
|
|
const delay = 5000; // Alle 5 Sekunden versuchen
|
|
console.log(`Warte ${delay}ms bis zum nächsten Reconnect-Versuch...`);
|
|
setTimeout(() => {
|
|
reconnectFn();
|
|
}, delay);
|
|
};
|
|
|
|
connectSocket();
|
|
}
|
|
},
|
|
initializeDaemonSocket({ commit, state }) {
|
|
if (!state.isLoggedIn || !state.user) {
|
|
return;
|
|
}
|
|
|
|
// Daemon URL für lokale Entwicklung und Produktion
|
|
let daemonUrl = import.meta.env.VITE_DAEMON_SOCKET;
|
|
|
|
// Für lokale Entwicklung: direkte Daemon-Verbindung
|
|
if (!daemonUrl && (import.meta.env.DEV || window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1')) {
|
|
daemonUrl = 'ws://localhost:4551';
|
|
}
|
|
|
|
// Fallback für Produktion
|
|
if (!daemonUrl) {
|
|
daemonUrl = 'wss://www.your-part.de:4551';
|
|
}
|
|
|
|
|
|
const connectDaemonSocket = () => {
|
|
// Protokoll-Fallback: zuerst mit Subprotokoll, dann ohne
|
|
const protocols = ['yourpart-protocol', undefined];
|
|
let attemptIndex = 0;
|
|
|
|
const tryConnectWithProtocol = () => {
|
|
const currentProtocol = protocols[attemptIndex];
|
|
try {
|
|
commit('setDaemonConnectionStatus', 'connecting');
|
|
const daemonSocket = currentProtocol
|
|
? new WebSocket(daemonUrl, currentProtocol)
|
|
: new WebSocket(daemonUrl);
|
|
|
|
let opened = false;
|
|
|
|
daemonSocket.onopen = () => {
|
|
opened = true;
|
|
retryCount = 0; // Reset retry counter on successful connection
|
|
commit('setDaemonConnectionStatus', 'connected');
|
|
const payload = JSON.stringify({
|
|
event: 'setUserId',
|
|
data: { userId: state.user.id }
|
|
});
|
|
daemonSocket.send(payload);
|
|
};
|
|
|
|
daemonSocket.onclose = (event) => {
|
|
commit('setDaemonConnectionStatus', 'disconnected');
|
|
// Falls Verbindungsaufbau nicht offen war und es noch einen Fallback gibt → nächsten Versuch ohne Subprotokoll
|
|
if (!opened && attemptIndex < protocols.length - 1) {
|
|
attemptIndex += 1;
|
|
tryConnectWithProtocol();
|
|
return;
|
|
}
|
|
retryConnection(connectDaemonSocket);
|
|
};
|
|
|
|
daemonSocket.onerror = (error) => {
|
|
commit('setDaemonConnectionStatus', 'error');
|
|
// Bei Fehler vor Open: Fallback versuchen
|
|
if (!opened && attemptIndex < protocols.length - 1) {
|
|
attemptIndex += 1;
|
|
tryConnectWithProtocol();
|
|
return;
|
|
}
|
|
retryConnection(connectDaemonSocket);
|
|
};
|
|
|
|
daemonSocket.addEventListener('message', (event) => {
|
|
const message = event.data;
|
|
if (message === "ping") {
|
|
daemonSocket.send("pong");
|
|
} else {
|
|
try {
|
|
const data = JSON.parse(message);
|
|
// Handle daemon messages here
|
|
} catch (error) {
|
|
// Error parsing daemon message
|
|
}
|
|
}
|
|
});
|
|
|
|
commit('setDaemonSocket', daemonSocket);
|
|
} catch (error) {
|
|
// Beim Konstruktionsfehler ebenfalls Fallback versuchen
|
|
if (attemptIndex < protocols.length - 1) {
|
|
attemptIndex += 1;
|
|
tryConnectWithProtocol();
|
|
return;
|
|
}
|
|
retryConnection(connectDaemonSocket);
|
|
}
|
|
};
|
|
|
|
tryConnectWithProtocol();
|
|
};
|
|
|
|
let retryCount = 0;
|
|
const maxRetries = 15; // Increased max retries
|
|
const retryConnection = (reconnectFn) => {
|
|
console.log(`Daemon-Reconnect-Versuch ${retryCount + 1}/${maxRetries}`);
|
|
if (retryCount >= maxRetries) {
|
|
// Nach maxRetries alle 5 Sekunden weiter versuchen
|
|
console.log('Daemon: Max Retries erreicht, versuche weiter alle 5 Sekunden...');
|
|
setTimeout(() => {
|
|
reconnectFn();
|
|
}, 5000);
|
|
return;
|
|
}
|
|
retryCount++;
|
|
const delay = 5000; // Alle 5 Sekunden versuchen
|
|
console.log(`Daemon: Warte ${delay}ms bis zum nächsten Reconnect-Versuch...`);
|
|
setTimeout(() => {
|
|
reconnectFn();
|
|
}, delay);
|
|
};
|
|
connectDaemonSocket();
|
|
},
|
|
setLanguage({ commit }, language) {
|
|
commit('setLanguage', language);
|
|
},
|
|
async loadMenu({ commit }) {
|
|
try {
|
|
const menu = await loadMenu();
|
|
commit('setMenu', menu);
|
|
} catch (err) {
|
|
commit('setMenu', []);
|
|
}
|
|
},
|
|
},
|
|
getters: {
|
|
isLoggedIn: state => state.isLoggedIn,
|
|
user: state => state.user,
|
|
language: state => state.language,
|
|
menu: state => state.menu,
|
|
socket: state => state.socket,
|
|
daemonSocket: state => state.daemonSocket,
|
|
menuNeedsUpdate: state => state.menuNeedsUpdate,
|
|
connectionStatus: state => state.connectionStatus,
|
|
daemonConnectionStatus: state => state.daemonConnectionStatus,
|
|
},
|
|
modules: {
|
|
dialogs,
|
|
},
|
|
});
|
|
|
|
if (store.state.isLoggedIn && store.state.user) {
|
|
store.dispatch('initializeSocket');
|
|
store.dispatch('initializeDaemonSocket');
|
|
}
|
|
|
|
export default store;
|