frontend: Improve webcomponent event and command types
This commit is contained in:
parent
e75b21fa49
commit
326ee174c6
@ -25,7 +25,8 @@ import {
|
|||||||
RoomService,
|
RoomService,
|
||||||
SessionStorageService
|
SessionStorageService
|
||||||
} from '../../services';
|
} from '../../services';
|
||||||
import { OpenViduMeetMessage, WebComponentEventType } from 'webcomponent/src/types/message.type';
|
import { OutboundEventMessage } from 'webcomponent/src/models/message.type';
|
||||||
|
import { WebComponentEvent } from 'webcomponent/src/models/event.model';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-video-room',
|
selector: 'app-video-room',
|
||||||
@ -114,11 +115,11 @@ export class VideoRoomComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onParticipantConnected(event: ParticipantModel) {
|
onParticipantConnected(event: ParticipantModel) {
|
||||||
const message: OpenViduMeetMessage = {
|
const message: OutboundEventMessage = {
|
||||||
eventType: WebComponentEventType.LOCAL_PARTICIPANT_CONNECTED,
|
event: WebComponentEvent.JOIN,
|
||||||
payload: {
|
payload: {
|
||||||
roomId: event.getProperties().room?.name,
|
roomId: event.getProperties().room?.name || '',
|
||||||
participantName: event.name
|
participantName: event.name!
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.wcManagerService.sendMessageToParent(message);
|
this.wcManagerService.sendMessageToParent(message);
|
||||||
@ -129,8 +130,8 @@ export class VideoRoomComponent implements OnInit, OnDestroy {
|
|||||||
const redirectURL = this.ctxService.getLeaveRedirectURL() || '/disconnected';
|
const redirectURL = this.ctxService.getLeaveRedirectURL() || '/disconnected';
|
||||||
const isExternalURL = /^https?:\/\//.test(redirectURL);
|
const isExternalURL = /^https?:\/\//.test(redirectURL);
|
||||||
|
|
||||||
const message: OpenViduMeetMessage = {
|
const message: OutboundEventMessage = {
|
||||||
eventType: WebComponentEventType.LOCAL_PARTICIPANT_LEFT,
|
event: WebComponentEvent.LEFT,
|
||||||
payload: {
|
payload: {
|
||||||
roomId: event.roomName,
|
roomId: event.roomName,
|
||||||
participantName: event.participantName
|
participantName: event.participantName
|
||||||
|
|||||||
@ -8,12 +8,8 @@ import {
|
|||||||
OpenViduService,
|
OpenViduService,
|
||||||
LoggerService
|
LoggerService
|
||||||
} from 'projects/shared-meet-components/src/public-api';
|
} from 'projects/shared-meet-components/src/public-api';
|
||||||
import {
|
import { WebComponentCommand } from 'webcomponent/src/models/command.model';
|
||||||
OpenViduMeetMessage,
|
import { OutboundEventMessage, InboundCommandMessage } from 'webcomponent/src/models/message.type';
|
||||||
ParentMessage,
|
|
||||||
WebComponentActionType,
|
|
||||||
WebComponentEventType
|
|
||||||
} from 'webcomponent/src/types/message.type';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to manage the commands from OpenVidu Meet WebComponent/Iframe.
|
* Service to manage the commands from OpenVidu Meet WebComponent/Iframe.
|
||||||
@ -43,12 +39,12 @@ export class WebComponentManagerService {
|
|||||||
this.isListenerStarted = true;
|
this.isListenerStarted = true;
|
||||||
// Listen for messages from the iframe
|
// Listen for messages from the iframe
|
||||||
window.addEventListener('message', async (event) => {
|
window.addEventListener('message', async (event) => {
|
||||||
const message: ParentMessage = event.data;
|
const message: InboundCommandMessage = event.data;
|
||||||
const parentDomain = this.contextService.getParentDomain();
|
const parentDomain = this.contextService.getParentDomain();
|
||||||
const { action, payload } = message;
|
const { command, payload } = message;
|
||||||
|
|
||||||
if (!parentDomain) {
|
if (!parentDomain) {
|
||||||
if (action === WebComponentActionType.INITIALIZE) {
|
if (command === WebComponentCommand.INITIALIZE) {
|
||||||
if (!payload || !('domain' in payload)) {
|
if (!payload || !('domain' in payload)) {
|
||||||
console.error('Parent domain not provided in message payload');
|
console.error('Parent domain not provided in message payload');
|
||||||
return;
|
return;
|
||||||
@ -66,19 +62,19 @@ export class WebComponentManagerService {
|
|||||||
|
|
||||||
console.debug('Message received from parent:', event.data);
|
console.debug('Message received from parent:', event.data);
|
||||||
// TODO: reject if room is not connected
|
// TODO: reject if room is not connected
|
||||||
switch (action) {
|
switch (command) {
|
||||||
case WebComponentActionType.END_MEETING:
|
case WebComponentCommand.END_MEETING:
|
||||||
// Moderator only
|
// Moderator only
|
||||||
if (this.contextService.isModeratorParticipant()) {
|
if (this.contextService.isModeratorParticipant()) {
|
||||||
const roomId = this.contextService.getRoomId();
|
const roomId = this.contextService.getRoomId();
|
||||||
await this.httpService.endMeeting(roomId);
|
await this.httpService.endMeeting(roomId);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WebComponentActionType.TOGGLE_CHAT:
|
// case WebComponentCommand.TOGGLE_CHAT:
|
||||||
// Toggle chat
|
// Toggle chat
|
||||||
this.panelService.togglePanel(PanelType.CHAT);
|
// this.panelService.togglePanel(PanelType.CHAT);
|
||||||
break;
|
// break;
|
||||||
case WebComponentActionType.LEAVE_ROOM:
|
case WebComponentCommand.LEAVE_ROOM:
|
||||||
// Leave room.
|
// Leave room.
|
||||||
await this.openviduService.disconnectRoom();
|
await this.openviduService.disconnectRoom();
|
||||||
break;
|
break;
|
||||||
@ -94,7 +90,7 @@ export class WebComponentManagerService {
|
|||||||
window.removeEventListener('message', this.startCommandsListener);
|
window.removeEventListener('message', this.startCommandsListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMessageToParent(event: OpenViduMeetMessage /*| RoomDisconnectedEvent*/) {
|
sendMessageToParent(event: OutboundEventMessage) {
|
||||||
if (!this.contextService.isEmbeddedMode()) return;
|
if (!this.contextService.isEmbeddedMode()) return;
|
||||||
this.log.d('Sending message to parent :', event);
|
this.log.d('Sending message to parent :', event);
|
||||||
const origin = this.contextService.getParentDomain();
|
const origin = this.contextService.getParentDomain();
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ParentMessage } from '../types/message.type';
|
import { InboundCommandMessage } from '../models/message.type';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles sending messages to the iframe.
|
* Handles sending messages to the iframe.
|
||||||
@ -12,7 +12,7 @@ export class CommandsManager {
|
|||||||
this.allowedOrigin = allowedOrigin;
|
this.allowedOrigin = allowedOrigin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public sendMessage(message: ParentMessage, targetOrigin?: string): void {
|
public sendMessage(message: InboundCommandMessage, targetOrigin?: string): void {
|
||||||
targetOrigin = targetOrigin || this.allowedOrigin;
|
targetOrigin = targetOrigin || this.allowedOrigin;
|
||||||
this.iframe.contentWindow?.postMessage(message, targetOrigin);
|
this.iframe.contentWindow?.postMessage(message, targetOrigin);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { OpenViduMeetMessage } from '../types/message.type';
|
import { OutboundEventMessage } from '../models/message.type';
|
||||||
|
|
||||||
export class EventsManager {
|
export class EventsManager {
|
||||||
private element: HTMLElement;
|
private element: HTMLElement;
|
||||||
@ -12,9 +12,9 @@ export class EventsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private handleMessage(event: MessageEvent) {
|
private handleMessage(event: MessageEvent) {
|
||||||
const message: OpenViduMeetMessage = event.data;
|
const message: OutboundEventMessage = event.data;
|
||||||
// Validate message origin (security measure)
|
// Validate message origin (security measure)
|
||||||
if (!message || !message.eventType) {
|
if (!message || !message.event) {
|
||||||
// console.warn('Invalid message:', message);
|
// console.warn('Invalid message:', message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -22,8 +22,8 @@ export class EventsManager {
|
|||||||
this.dispatchEvent(message);
|
this.dispatchEvent(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private dispatchEvent(message: OpenViduMeetMessage) {
|
private dispatchEvent(message: OutboundEventMessage) {
|
||||||
const event = new CustomEvent(message.eventType, {
|
const event = new CustomEvent(message.event, {
|
||||||
detail: message.payload,
|
detail: message.payload,
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true
|
composed: true
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { ParentMessage, WebComponentActionType } from '../types/message.type';
|
import { WebComponentCommand } from '../models/command.model';
|
||||||
|
import { InboundCommandMessage } from '../models/message.type';
|
||||||
import { CommandsManager } from './CommandsManager';
|
import { CommandsManager } from './CommandsManager';
|
||||||
import { EventsManager } from './EventsManager';
|
import { EventsManager } from './EventsManager';
|
||||||
|
|
||||||
@ -68,8 +69,8 @@ export class OpenViduMeet extends HTMLElement {
|
|||||||
this.shadowRoot?.appendChild(style);
|
this.shadowRoot?.appendChild(style);
|
||||||
this.shadowRoot?.appendChild(this.iframe);
|
this.shadowRoot?.appendChild(this.iframe);
|
||||||
this.iframe.onload = () => {
|
this.iframe.onload = () => {
|
||||||
const message: ParentMessage = {
|
const message: InboundCommandMessage = {
|
||||||
action: WebComponentActionType.INITIALIZE,
|
command: WebComponentCommand.INITIALIZE,
|
||||||
payload: { domain: window.location.origin }
|
payload: { domain: window.location.origin }
|
||||||
};
|
};
|
||||||
this.commandsManager.sendMessage(message);
|
this.commandsManager.sendMessage(message);
|
||||||
@ -101,17 +102,17 @@ export class OpenViduMeet extends HTMLElement {
|
|||||||
// Public methods
|
// Public methods
|
||||||
|
|
||||||
public endMeeting() {
|
public endMeeting() {
|
||||||
const message: ParentMessage = { action: WebComponentActionType.END_MEETING };
|
const message: InboundCommandMessage = { command: WebComponentCommand.END_MEETING };
|
||||||
this.commandsManager.sendMessage(message);
|
this.commandsManager.sendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public leaveRoom() {
|
public leaveRoom() {
|
||||||
const message: ParentMessage = { action: WebComponentActionType.LEAVE_ROOM };
|
const message: InboundCommandMessage = { command: WebComponentCommand.LEAVE_ROOM };
|
||||||
this.commandsManager.sendMessage(message);
|
this.commandsManager.sendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public toggleChat() {
|
// public toggleChat() {
|
||||||
const message: ParentMessage = { action: WebComponentActionType.TOGGLE_CHAT };
|
// const message: ParentMessage = { action: WebComponentActionType.TOGGLE_CHAT };
|
||||||
this.commandsManager.sendMessage(message);
|
// this.commandsManager.sendMessage(message);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
49
frontend/webcomponent/src/models/command.model.ts
Normal file
49
frontend/webcomponent/src/models/command.model.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* All available commands that can be sent to the WebComponent.
|
||||||
|
*/
|
||||||
|
export enum WebComponentCommand {
|
||||||
|
/**
|
||||||
|
* Initializes the WebComponent with the given configuration.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
INITIALIZE = 'INITIALIZE',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ends the current meeting for all participants.
|
||||||
|
* This command is only available for the moderator.
|
||||||
|
*/
|
||||||
|
END_MEETING = 'END_MEETING',
|
||||||
|
/**
|
||||||
|
* Disconnects the local participant from the current room.
|
||||||
|
*/
|
||||||
|
LEAVE_ROOM = 'LEAVE_ROOM'
|
||||||
|
// TOGGLE_CHAT = 'TOGGLE_CHAT'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type definitions for command payloads.
|
||||||
|
* Each property corresponds to a command in {@link WebComponentCommand}.
|
||||||
|
* @category Communication
|
||||||
|
*/
|
||||||
|
export interface CommandPayloads {
|
||||||
|
/**
|
||||||
|
* Payload for the INITIALIZE command.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
[WebComponentCommand.INITIALIZE]: {
|
||||||
|
domain: string;
|
||||||
|
};
|
||||||
|
[WebComponentCommand.END_MEETING]: void;
|
||||||
|
[WebComponentCommand.LEAVE_ROOM]: void;
|
||||||
|
// [WebComponentCommand.TOGGLE_CHAT]: void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the type-safe payload for a specific command.
|
||||||
|
* This type allows TypeScript to infer the correct payload type based on the command.
|
||||||
|
* @category Type Helpers
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
export type CommandPayloadFor<T extends WebComponentCommand> = T extends keyof CommandPayloads
|
||||||
|
? CommandPayloads[T]
|
||||||
|
: never;
|
||||||
45
frontend/webcomponent/src/models/event.model.ts
Normal file
45
frontend/webcomponent/src/models/event.model.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* All available events that can be emitted by the WebComponent.
|
||||||
|
* @category Communication
|
||||||
|
*/
|
||||||
|
export enum WebComponentEvent {
|
||||||
|
/**
|
||||||
|
* Event emitted when the local participant joins the room.
|
||||||
|
*/
|
||||||
|
JOIN = 'JOIN',
|
||||||
|
/**
|
||||||
|
* Event emitted when the local participant leaves the room.
|
||||||
|
*/
|
||||||
|
LEFT = 'LEFT',
|
||||||
|
/**
|
||||||
|
* Event emitted when a moderator ends the meeting.
|
||||||
|
*/
|
||||||
|
MEETING_ENDED = 'MEETING_ENDED'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type definitions for event payloads.
|
||||||
|
* Each property corresponds to an event in {@link WebComponentEvent}.
|
||||||
|
* @category Communication
|
||||||
|
*/
|
||||||
|
export interface EventPayloads {
|
||||||
|
[WebComponentEvent.JOIN]: {
|
||||||
|
roomId: string;
|
||||||
|
participantName: string;
|
||||||
|
};
|
||||||
|
[WebComponentEvent.LEFT]: {
|
||||||
|
roomId: string;
|
||||||
|
participantName: string;
|
||||||
|
};
|
||||||
|
[WebComponentEvent.MEETING_ENDED]: {
|
||||||
|
roomId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the type-safe payload for a specific event.
|
||||||
|
* This type allows TypeScript to infer the correct payload type based on the event.
|
||||||
|
* @category Type Helpers
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
export type EventPayloadFor<T extends WebComponentEvent> = T extends keyof EventPayloads ? EventPayloads[T] : never;
|
||||||
62
frontend/webcomponent/src/models/message.type.ts
Normal file
62
frontend/webcomponent/src/models/message.type.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { CommandPayloadFor, WebComponentCommand } from './command.model';
|
||||||
|
import { EventPayloadFor, WebComponentEvent } from './event.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents all possible messages exchanged between the host application and WebComponent.
|
||||||
|
* @category Communication
|
||||||
|
*/
|
||||||
|
export type WebComponentMessage = InboundCommandMessage<WebComponentCommand> | OutboundEventMessage<WebComponentEvent>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message sent from the host application to the WebComponent.
|
||||||
|
* Contains a command with an optional type-safe payload.
|
||||||
|
* @category Communication
|
||||||
|
*/
|
||||||
|
export interface InboundCommandMessage<T extends WebComponentCommand = WebComponentCommand> {
|
||||||
|
/** The command to execute in the WebComponent */
|
||||||
|
command: T;
|
||||||
|
/** Optional payload with additional data for the command */
|
||||||
|
payload?: CommandPayloadFor<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message sent from the WebComponent to the host application.
|
||||||
|
* Contains an event type with an optional type-safe payload.
|
||||||
|
* @category Communication
|
||||||
|
*/
|
||||||
|
export interface OutboundEventMessage<T extends WebComponentEvent = WebComponentEvent> {
|
||||||
|
/** The type of event being emitted */
|
||||||
|
event: T;
|
||||||
|
/** Optional payload with additional data about the event */
|
||||||
|
payload?: EventPayloadFor<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to create a properly typed command message.
|
||||||
|
* @param command The command to send
|
||||||
|
* @param payload The payload for the command
|
||||||
|
* @returns A properly formatted command message
|
||||||
|
* @category Utilities
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
export function createCommandMessage<T extends WebComponentCommand>(
|
||||||
|
command: T,
|
||||||
|
payload?: CommandPayloadFor<T>
|
||||||
|
): InboundCommandMessage<T> {
|
||||||
|
return { command, payload };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to create a properly typed event message.
|
||||||
|
* @param event The event type
|
||||||
|
* @param payload The payload for the event
|
||||||
|
* @returns A properly formatted event message
|
||||||
|
* @category Utilities
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
export function createEventMessage<T extends WebComponentEvent>(
|
||||||
|
event: T,
|
||||||
|
payload?: EventPayloadFor<T>
|
||||||
|
): OutboundEventMessage<T> {
|
||||||
|
return { event, payload };
|
||||||
|
}
|
||||||
@ -1,29 +0,0 @@
|
|||||||
export type WebComponentMessage = ParentMessage | OpenViduMeetMessage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Message sent from the parent to the OpenViduMeet component.
|
|
||||||
*/
|
|
||||||
export interface ParentMessage {
|
|
||||||
action: WebComponentActionType;
|
|
||||||
payload?: Record<string, any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Message sent from the OpenViduMeet component to the parent.
|
|
||||||
*/
|
|
||||||
export interface OpenViduMeetMessage {
|
|
||||||
eventType: WebComponentEventType;
|
|
||||||
payload?: Record<string, unknown>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum WebComponentActionType {
|
|
||||||
INITIALIZE = 'initialize',
|
|
||||||
END_MEETING = 'endMeeting',
|
|
||||||
LEAVE_ROOM = 'leaveRoom',
|
|
||||||
TOGGLE_CHAT = 'toggleChat'
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum WebComponentEventType {
|
|
||||||
LOCAL_PARTICIPANT_CONNECTED = 'join',
|
|
||||||
LOCAL_PARTICIPANT_LEFT = 'left'
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user