Add ChatInfoService for retrieving player and party names: integrated backend APIs, updated chat service with caching logic for names, and extended OpenAPI documentation.

This commit is contained in:
2026-08-01 20:22:38 +02:00
parent 79a62e9ce9
commit 8ecfb99b27
8 changed files with 207 additions and 105 deletions
@@ -6,6 +6,7 @@ import {RawChatMessage} from '@pages/altitude/chat/objects/raw-chat-message.obje
import {normalizeComponent} from '@pages/altitude/chat/mini-message/normalize.util';
import {ChatChannel} from '@pages/altitude/chat/objects/chat-channel.object';
import {NotificationService} from '@pages/altitude/chat/service/chat-notification.service';
import {ChatInfoService} from '@api';
interface SsePayloadEvent {
data: string;
@@ -16,11 +17,16 @@ export class ChatService implements OnDestroy {
private eventSource?: EventSourcePolyfill;
private readonly notificationService: NotificationService = inject(NotificationService);
private readonly authService: AuthService = inject(AuthService)
private readonly chatInfoService: ChatInfoService = inject(ChatInfoService);
private readonly _messages = signal<ChatMessage[]>([])
private readonly _channels = signal<ChatChannel[]>([])
public readonly channels = computed(() => this._channels().sort((a, b) => a.name.localeCompare(b.name)));
private readonly _selectedChannel = signal<ChatChannel | null>(null);
public readonly selectedChannel = this._selectedChannel.asReadonly()
public readonly partieMap = signal<Map<string, string>>(new Map());
public readonly userNameMap = signal<Map<string, string>>(new Map());
private readonly pendingPartyNameRequests = new Set<string>();
private readonly pendingUserNameRequests = new Set<string>();
public readonly messages = computed(() => {
const selected = this._selectedChannel();
@@ -109,18 +115,72 @@ export class ChatService implements OnDestroy {
return {name: 'Global Admin Chat', type: 'GAC'};
}
if (message.type === 'PARTY') {
if (!message.channelName) {
throw new Error('Party name is missing');
}
this.updatePartyMap(message.channelName)
return {name: message.channel, type: 'PARTY'};
}
if (message.type === 'MSG') {
const uuid = this.authService.getUuid();
if (message.uuid === uuid) {
this.updateUserNameMap(message.receiver)
return {name: message.receiver, type: 'DM'};
}
this.updateUserNameMap(message.uuid)
return {name: message.uuid, type: 'DM'};
}
return {name: message.server, type: 'SERVER'};
}
public updatePartyMap(partieId: string): void {
if (this.partieMap().has(partieId) || this.pendingPartyNameRequests.has(partieId)) {
return;
}
this.pendingPartyNameRequests.add(partieId);
this.chatInfoService.getPartyName(partieId).subscribe({
next: (partyName) => {
this.partieMap.update((old) => {
const newMap = new Map(old);
newMap.set(partieId, partyName);
return newMap;
});
},
error: (error) => {
console.error(`Failed to load party name for ${partieId}:`, error);
},
complete: () => {
this.pendingPartyNameRequests.delete(partieId);
}
});
}
public updateUserNameMap(uuid: string): void {
if (this.userNameMap().has(uuid) || this.pendingUserNameRequests.has(uuid)) {
return;
}
this.pendingUserNameRequests.add(uuid);
this.chatInfoService.getName(uuid).subscribe({
next: (userName) => {
this.userNameMap.update((old) => {
const newMap = new Map(old);
newMap.set(uuid, userName.nickname ?? userName.name);
return newMap;
});
},
error: (error) => {
console.error(`Failed to load username for ${uuid}:`, error);
},
complete: () => {
this.pendingUserNameRequests.delete(uuid);
}
});
}
public selectChannel(channel: ChatChannel) {
this._selectedChannel.set(channel);
this._channels.update((old) =>