Files
svelte-mud/src/lib/profiles/ProfileManager.ts

304 lines
8.0 KiB
TypeScript
Raw Normal View History

2025-04-21 14:12:36 +02:00
import { EventEmitter } from '$lib/utils/EventEmitter';
export interface MudProfile {
id: string;
name: string;
host: string;
port: number;
useSSL: boolean;
autoLogin?: {
enabled: boolean;
username: string;
password: string;
commands: string[];
};
triggers?: string; // JSON string of triggers
aliases?: {
[key: string]: string;
};
macros?: {
[key: string]: string;
};
gmcpPackages?: string[]; // Additional GMCP packages to support
font?: string;
fontSize?: number;
theme?: string;
ansiColor: boolean;
accessibilityOptions?: {
textToSpeech: boolean;
highContrast: boolean;
speechRate: number;
speechPitch: number;
speechVolume: number;
};
}
export class ProfileManager extends EventEmitter {
private profiles: MudProfile[] = [];
private activeProfileId: string | null = null;
private storageKey = 'svelte-mud-profiles';
constructor() {
super();
this.loadProfiles();
}
/**
* Load profiles from local storage
*/
private loadProfiles(): void {
if (typeof window === 'undefined') {
return; // Skip during SSR
}
try {
const storedProfiles = localStorage.getItem(this.storageKey);
2025-04-22 13:54:57 +02:00
console.log('Retrieved from localStorage:', storedProfiles);
2025-04-21 14:12:36 +02:00
if (storedProfiles) {
2025-04-22 13:54:57 +02:00
const parsed = JSON.parse(storedProfiles);
console.log('Parsed profiles:', parsed);
// Validate profiles before assigning
if (Array.isArray(parsed)) {
// Filter out invalid profiles
this.profiles = parsed.filter(profile => this.isValidProfile(profile));
console.log('Loaded profiles from localStorage:', this.profiles);
if (this.profiles.length > 0) {
this.emit('profilesLoaded', this.profiles);
return; // Success, exit early
} else {
console.warn('No valid profiles found in stored data, creating default');
}
} else {
console.warn('Stored profiles data is not an array, creating default');
}
2025-04-21 14:12:36 +02:00
} else {
console.log('No profiles found in localStorage, creating default profile');
}
2025-04-22 13:54:57 +02:00
// If we got here, we need to create a default profile
const defaultProfile = this.createDefaultProfile();
defaultProfile.name = 'Aardwolf MUD';
defaultProfile.host = 'aardmud.org';
defaultProfile.port = 23;
// Clear profiles array and add the default
this.profiles = [];
this.addProfile(defaultProfile);
2025-04-21 14:12:36 +02:00
} catch (error) {
console.error('Failed to load profiles from local storage:', error);
2025-04-22 13:54:57 +02:00
console.error('Error details:', error.message, error.stack);
2025-04-21 14:12:36 +02:00
// Add a default profile if there was an error
const defaultProfile = this.createDefaultProfile();
defaultProfile.name = 'Aardwolf MUD';
defaultProfile.host = 'aardmud.org';
defaultProfile.port = 23;
2025-04-22 13:54:57 +02:00
// Clear profiles array and add the default
this.profiles = [];
2025-04-21 14:12:36 +02:00
this.addProfile(defaultProfile);
}
}
/**
* Save profiles to local storage
*/
private saveProfiles(): void {
if (typeof window === 'undefined') {
return; // Skip during SSR
}
try {
2025-04-22 13:54:57 +02:00
// Add logging to help debug
console.log('Saving profiles to localStorage:', this.profiles);
const profilesJson = JSON.stringify(this.profiles);
console.log('Profiles JSON:', profilesJson);
localStorage.setItem(this.storageKey, profilesJson);
console.log('Profiles saved successfully');
// Validate by reading back
const readBack = localStorage.getItem(this.storageKey);
console.log('Read back from localStorage:', readBack);
2025-04-21 14:12:36 +02:00
} catch (error) {
console.error('Failed to save profiles to local storage:', error);
2025-04-22 13:54:57 +02:00
console.error('Error details:', error.message, error.stack);
2025-04-21 14:12:36 +02:00
}
}
/**
* Add a new profile
*/
public addProfile(profile: MudProfile): void {
// Ensure all required fields are present
if (!profile.id) {
profile.id = `profile-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
}
if (profile.useSSL === undefined) {
profile.useSSL = false;
}
if (profile.ansiColor === undefined) {
profile.ansiColor = true;
}
// Check if a profile with the same ID already exists
const existingIndex = this.profiles.findIndex(p => p.id === profile.id);
if (existingIndex !== -1) {
// Update existing profile
this.profiles[existingIndex] = profile;
console.log(`Updated profile ${profile.id} (${profile.name})`, profile);
this.emit('profileUpdated', profile);
} else {
// Add new profile
this.profiles.push(profile);
console.log(`Added new profile ${profile.id} (${profile.name})`, profile);
this.emit('profileAdded', profile);
}
// Save to storage
this.saveProfiles();
}
/**
* Remove a profile by ID
*/
public removeProfile(profileId: string): void {
const index = this.profiles.findIndex(p => p.id === profileId);
if (index !== -1) {
const removedProfile = this.profiles[index];
this.profiles.splice(index, 1);
// If the active profile was removed, clear the active profile
if (this.activeProfileId === profileId) {
this.activeProfileId = null;
this.emit('activeProfileChanged', null);
}
this.emit('profileRemoved', removedProfile);
this.saveProfiles();
}
}
/**
* Get all profiles
*/
public getProfiles(): MudProfile[] {
return [...this.profiles];
}
/**
* Get a profile by ID
*/
public getProfile(profileId: string): MudProfile | undefined {
return this.profiles.find(p => p.id === profileId);
}
/**
* Set the active profile
*/
public setActiveProfile(profileId: string): void {
const profile = this.getProfile(profileId);
if (profile) {
this.activeProfileId = profileId;
this.emit('activeProfileChanged', profile);
} else {
throw new Error(`Profile with ID ${profileId} not found`);
}
}
/**
* Get the active profile
*/
public getActiveProfile(): MudProfile | null {
if (!this.activeProfileId) return null;
const activeProfile = this.getProfile(this.activeProfileId);
return activeProfile || null;
}
/**
* Import profiles from a JSON string
*/
public importProfiles(json: string): void {
try {
const imported = JSON.parse(json);
if (Array.isArray(imported)) {
imported.forEach(profile => {
if (this.isValidProfile(profile)) {
this.addProfile(profile);
}
});
}
this.emit('profilesImported', imported);
} catch (error) {
console.error('Failed to import profiles:', error);
throw new Error('Failed to import profiles. Invalid format.');
}
}
/**
* Export profiles to a JSON string
*/
public exportProfiles(): string {
return JSON.stringify(this.profiles, null, 2);
}
/**
* Validate a profile object
*/
private isValidProfile(obj: any): boolean {
return (
typeof obj === 'object' &&
typeof obj.id === 'string' &&
typeof obj.name === 'string' &&
typeof obj.host === 'string' &&
typeof obj.port === 'number' &&
typeof obj.useSSL === 'boolean' &&
typeof obj.ansiColor === 'boolean'
);
}
/**
* Create a default profile
*/
public createDefaultProfile(): MudProfile {
const id = `profile-${Date.now()}`;
return {
id,
name: 'New Profile',
host: 'mud.example.com',
port: 23,
useSSL: false,
ansiColor: true,
autoLogin: {
enabled: false,
username: '',
password: '',
commands: []
},
aliases: {},
macros: {},
gmcpPackages: [],
accessibilityOptions: {
textToSpeech: false,
highContrast: false,
speechRate: 1,
speechPitch: 1,
speechVolume: 1
}
};
}
}