mirror of https://github.com/OpenVidu/openvidu.git
ov-components: Refactor prejoin logic and improve observable handling in configuration service
parent
bcbf24b84d
commit
1762c43769
|
@ -10,7 +10,7 @@ import {
|
||||||
Output
|
Output
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
import { animate, state, style, transition, trigger } from '@angular/animations';
|
||||||
import { filter, Subject, takeUntil, tap } from 'rxjs';
|
import { filter, Subject, take, takeUntil, tap } from 'rxjs';
|
||||||
import { ILogger } from '../../models/logger.model';
|
import { ILogger } from '../../models/logger.model';
|
||||||
import { CdkOverlayService } from '../../services/cdk-overlay/cdk-overlay.service';
|
import { CdkOverlayService } from '../../services/cdk-overlay/cdk-overlay.service';
|
||||||
import { OpenViduComponentsConfigService } from '../../services/config/directive-config.service';
|
import { OpenViduComponentsConfigService } from '../../services/config/directive-config.service';
|
||||||
|
@ -175,15 +175,12 @@ export class PreJoinComponent implements OnInit, OnDestroy {
|
||||||
if (this.participantName?.trim()) {
|
if (this.participantName?.trim()) {
|
||||||
this.libService.updateGeneralConfig({ participantName: this.participantName.trim() });
|
this.libService.updateGeneralConfig({ participantName: this.participantName.trim() });
|
||||||
|
|
||||||
// Wait for the next tick to ensure the participant name propagates
|
|
||||||
// through the observable before emitting onReadyToJoin
|
|
||||||
this.libService.participantName$
|
this.libService.participantName$
|
||||||
.pipe(
|
.pipe(
|
||||||
takeUntil(this.destroy$),
|
|
||||||
filter((name) => name === this.participantName?.trim()),
|
filter((name) => name === this.participantName?.trim()),
|
||||||
tap(() => this.onReadyToJoin.emit())
|
take(1)
|
||||||
)
|
)
|
||||||
.subscribe();
|
.subscribe(() => this.onReadyToJoin.emit());
|
||||||
} else {
|
} else {
|
||||||
// No participant name to set, emit immediately
|
// No participant name to set, emit immediately
|
||||||
this.onReadyToJoin.emit();
|
this.onReadyToJoin.emit();
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
[(ngModel)]="name"
|
[(ngModel)]="name"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
[disabled]="!isPrejoinPage"
|
[disabled]="!isPrejoinPage"
|
||||||
(change)="updateName()"
|
(input)="updateName()"
|
||||||
(keypress)="eventKeyPress($event)"
|
(keypress)="eventKeyPress($event)"
|
||||||
[placeholder]="'PREJOIN.NICKNAME' | translate"
|
[placeholder]="'PREJOIN.NICKNAME' | translate"
|
||||||
class="name-input-field"
|
class="name-input-field"
|
||||||
|
|
|
@ -836,7 +836,6 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit {
|
||||||
*/
|
*/
|
||||||
_onReadyToJoin(): void {
|
_onReadyToJoin(): void {
|
||||||
this.log.d('Ready to join - initializing room and handling prejoin flow');
|
this.log.d('Ready to join - initializing room and handling prejoin flow');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Mark that user has initiated the join process
|
// Mark that user has initiated the join process
|
||||||
this.updateComponentState({
|
this.updateComponentState({
|
||||||
|
@ -921,15 +920,7 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit {
|
||||||
this.openviduService.initializeAndSetToken(token, livekitUrl);
|
this.openviduService.initializeAndSetToken(token, livekitUrl);
|
||||||
this.log.d('Token has been successfully set. Room is ready to join');
|
this.log.d('Token has been successfully set. Room is ready to join');
|
||||||
|
|
||||||
// Only update showPrejoin if user hasn't initiated join process yet
|
if (this.hasUserInitiatedJoin()) {
|
||||||
// This prevents prejoin from showing again after user clicked join
|
|
||||||
if (!this.hasUserInitiatedJoin()) {
|
|
||||||
this.updateComponentState({
|
|
||||||
state: VideoconferenceState.PREJOIN_SHOWN,
|
|
||||||
isRoomReady: true,
|
|
||||||
showPrejoin: this.libService.showPrejoin()
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// User has initiated join, proceed to hide prejoin and continue
|
// User has initiated join, proceed to hide prejoin and continue
|
||||||
this.log.d('User has initiated join, hiding prejoin and proceeding');
|
this.log.d('User has initiated join, hiding prejoin and proceeding');
|
||||||
this.updateComponentState({
|
this.updateComponentState({
|
||||||
|
@ -937,6 +928,21 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit {
|
||||||
isRoomReady: true,
|
isRoomReady: true,
|
||||||
showPrejoin: false
|
showPrejoin: false
|
||||||
});
|
});
|
||||||
|
console.log(this.componentState);
|
||||||
|
console.warn(
|
||||||
|
this.componentState.isRoomReady &&
|
||||||
|
!this.componentState.showPrejoin &&
|
||||||
|
!this.componentState.isLoading &&
|
||||||
|
!this.componentState.error?.hasError
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Only update showPrejoin if user hasn't initiated join process yet
|
||||||
|
// This prevents prejoin from showing again after user clicked join
|
||||||
|
this.updateComponentState({
|
||||||
|
state: VideoconferenceState.PREJOIN_SHOWN,
|
||||||
|
isRoomReady: true,
|
||||||
|
showPrejoin: this.libService.showPrejoin()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.log.e('Error trying to set token', error);
|
this.log.e('Error trying to set token', error);
|
||||||
|
|
|
@ -199,10 +199,7 @@ export class OpenViduComponentsConfigService {
|
||||||
*/
|
*/
|
||||||
private createGeneralConfigItem(initialValue: GeneralConfig): ConfigItem<GeneralConfig> {
|
private createGeneralConfigItem(initialValue: GeneralConfig): ConfigItem<GeneralConfig> {
|
||||||
const subject = new BehaviorSubject<GeneralConfig>(initialValue);
|
const subject = new BehaviorSubject<GeneralConfig>(initialValue);
|
||||||
const observable$ = subject.asObservable().pipe(
|
const observable$ = subject.asObservable();
|
||||||
distinctUntilChanged((prev, curr) => this.compareGeneralConfig(prev, curr)),
|
|
||||||
shareReplay(1)
|
|
||||||
);
|
|
||||||
return { subject, observable$ };
|
return { subject, observable$ };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +294,7 @@ export class OpenViduComponentsConfigService {
|
||||||
* Compare GeneralConfig efficiently
|
* Compare GeneralConfig efficiently
|
||||||
*/
|
*/
|
||||||
private compareGeneralConfig(prev: GeneralConfig, curr: GeneralConfig): boolean {
|
private compareGeneralConfig(prev: GeneralConfig, curr: GeneralConfig): boolean {
|
||||||
return (
|
const equal =
|
||||||
prev.token === curr.token &&
|
prev.token === curr.token &&
|
||||||
prev.livekitUrl === curr.livekitUrl &&
|
prev.livekitUrl === curr.livekitUrl &&
|
||||||
prev.tokenError === curr.tokenError &&
|
prev.tokenError === curr.tokenError &&
|
||||||
|
@ -306,8 +303,12 @@ export class OpenViduComponentsConfigService {
|
||||||
prev.prejoin === curr.prejoin &&
|
prev.prejoin === curr.prejoin &&
|
||||||
prev.prejoinDisplayParticipantName === curr.prejoinDisplayParticipantName &&
|
prev.prejoinDisplayParticipantName === curr.prejoinDisplayParticipantName &&
|
||||||
prev.showDisconnectionDialog === curr.showDisconnectionDialog &&
|
prev.showDisconnectionDialog === curr.showDisconnectionDialog &&
|
||||||
prev.recordingStreamBaseUrl === curr.recordingStreamBaseUrl
|
prev.recordingStreamBaseUrl === curr.recordingStreamBaseUrl;
|
||||||
);
|
|
||||||
|
if (!equal) {
|
||||||
|
console.log('GeneralConfig cambió', { prev, curr });
|
||||||
|
}
|
||||||
|
return equal;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grouped configuration items by domain
|
// Grouped configuration items by domain
|
||||||
|
@ -380,17 +381,51 @@ export class OpenViduComponentsConfigService {
|
||||||
private layoutRemoteParticipantsConfig = this.createConfigItem<ParticipantModel[] | undefined>(undefined);
|
private layoutRemoteParticipantsConfig = this.createConfigItem<ParticipantModel[] | undefined>(undefined);
|
||||||
|
|
||||||
// General observables
|
// General observables
|
||||||
token$: Observable<string> = this.generalConfig.observable$.pipe(map((config) => config.token));
|
token$: Observable<string> = this.generalConfig.observable$.pipe(
|
||||||
livekitUrl$: Observable<string> = this.generalConfig.observable$.pipe(map((config) => config.livekitUrl));
|
map((config) => config.token),
|
||||||
tokenError$: Observable<any> = this.generalConfig.observable$.pipe(map((config) => config.tokenError));
|
distinctUntilChanged(),
|
||||||
minimal$: Observable<boolean> = this.generalConfig.observable$.pipe(map((config) => config.minimal));
|
shareReplay(1)
|
||||||
participantName$: Observable<string> = this.generalConfig.observable$.pipe(map((config) => config.participantName));
|
);
|
||||||
prejoin$: Observable<boolean> = this.generalConfig.observable$.pipe(map((config) => config.prejoin));
|
livekitUrl$: Observable<string> = this.generalConfig.observable$.pipe(
|
||||||
prejoinDisplayParticipantName$: Observable<boolean> = this.generalConfig.observable$.pipe(
|
map((config) => config.livekitUrl),
|
||||||
map((config) => config.prejoinDisplayParticipantName)
|
distinctUntilChanged(),
|
||||||
|
shareReplay(1)
|
||||||
|
);
|
||||||
|
tokenError$: Observable<any> = this.generalConfig.observable$.pipe(
|
||||||
|
map((config) => config.tokenError),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
shareReplay(1)
|
||||||
|
);
|
||||||
|
minimal$: Observable<boolean> = this.generalConfig.observable$.pipe(
|
||||||
|
map((config) => config.minimal),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
shareReplay(1)
|
||||||
|
);
|
||||||
|
participantName$: Observable<string> = this.generalConfig.observable$.pipe(
|
||||||
|
map((config) => config.participantName),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
shareReplay(1)
|
||||||
|
);
|
||||||
|
prejoin$: Observable<boolean> = this.generalConfig.observable$.pipe(
|
||||||
|
map((config) => config.prejoin),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
shareReplay(1)
|
||||||
|
);
|
||||||
|
prejoinDisplayParticipantName$: Observable<boolean> = this.generalConfig.observable$.pipe(
|
||||||
|
map((config) => config.prejoinDisplayParticipantName),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
shareReplay(1)
|
||||||
|
);
|
||||||
|
showDisconnectionDialog$: Observable<boolean> = this.generalConfig.observable$.pipe(
|
||||||
|
map((config) => config.showDisconnectionDialog),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
shareReplay(1)
|
||||||
|
);
|
||||||
|
recordingStreamBaseUrl$: Observable<string> = this.generalConfig.observable$.pipe(
|
||||||
|
map((config) => config.recordingStreamBaseUrl),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
shareReplay(1)
|
||||||
);
|
);
|
||||||
showDisconnectionDialog$: Observable<boolean> = this.generalConfig.observable$.pipe(map((config) => config.showDisconnectionDialog));
|
|
||||||
recordingStreamBaseUrl$: Observable<string> = this.generalConfig.observable$.pipe(map((config) => config.recordingStreamBaseUrl));
|
|
||||||
|
|
||||||
// Stream observables
|
// Stream observables
|
||||||
videoEnabled$: Observable<boolean> = this.streamConfig.observable$.pipe(map((config) => config.videoEnabled));
|
videoEnabled$: Observable<boolean> = this.streamConfig.observable$.pipe(map((config) => config.videoEnabled));
|
||||||
|
|
|
@ -177,16 +177,20 @@ export class OpenViduService {
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
initializeAndSetToken(token: string, livekitUrl: string): void {
|
initializeAndSetToken(token: string, livekitUrl?: string): void {
|
||||||
const livekitData = this.extractLivekitData(token, livekitUrl);
|
const { livekitUrl: urlFromToken } = this.extractLivekitData(token);
|
||||||
this.livekitToken = token;
|
|
||||||
this.livekitUrl = livekitData.livekitUrl;
|
|
||||||
|
|
||||||
if (!this.livekitUrl) {
|
this.livekitToken = token;
|
||||||
|
const url = livekitUrl || urlFromToken;
|
||||||
|
|
||||||
|
if (!url) {
|
||||||
this.log.e('LiveKit URL is not defined. Please, check the livekitUrl parameter of the VideoConferenceComponent');
|
this.log.e('LiveKit URL is not defined. Please, check the livekitUrl parameter of the VideoConferenceComponent');
|
||||||
throw new Error('Livekit URL is not defined');
|
throw new Error('Livekit URL is not defined');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.livekitUrl = url;
|
||||||
|
// this.livekitRoomAdmin = !!livekitRoomAdmin;
|
||||||
|
|
||||||
// Initialize room if it doesn't exist yet
|
// Initialize room if it doesn't exist yet
|
||||||
// This ensures that getRoom() won't fail if token is set before onTokenRequested
|
// This ensures that getRoom() won't fail if token is set before onTokenRequested
|
||||||
if (!this.room) {
|
if (!this.room) {
|
||||||
|
@ -370,9 +374,8 @@ export class OpenViduService {
|
||||||
* @throws Error if there is an error decoding and parsing the token.
|
* @throws Error if there is an error decoding and parsing the token.
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
private extractLivekitData(token: string, livekitUrl: string): { livekitUrl: string; livekitRoomAdmin: boolean } {
|
private extractLivekitData(token: string): { livekitUrl?: string; livekitRoomAdmin: boolean } {
|
||||||
try {
|
try {
|
||||||
const response = { livekitUrl, livekitRoomAdmin: false };
|
|
||||||
const base64Url = token.split('.')[1];
|
const base64Url = token.split('.')[1];
|
||||||
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
||||||
const jsonPayload = decodeURIComponent(
|
const jsonPayload = decodeURIComponent(
|
||||||
|
@ -388,13 +391,13 @@ export class OpenViduService {
|
||||||
const payload = JSON.parse(jsonPayload);
|
const payload = JSON.parse(jsonPayload);
|
||||||
if (payload?.metadata) {
|
if (payload?.metadata) {
|
||||||
const tokenMetadata = JSON.parse(payload.metadata);
|
const tokenMetadata = JSON.parse(payload.metadata);
|
||||||
if (tokenMetadata.livekitUrl) {
|
return {
|
||||||
response.livekitUrl = tokenMetadata.livekitUrl;
|
livekitUrl: tokenMetadata.livekitUrl,
|
||||||
}
|
livekitRoomAdmin: !!tokenMetadata.roomAdmin
|
||||||
response.livekitRoomAdmin = tokenMetadata.roomAdmin;
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return { livekitRoomAdmin: false };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error('Error decoding and parsing token: ' + error);
|
throw new Error('Error decoding and parsing token: ' + error);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue