Skip to content
This repository has been archived by the owner on Oct 18, 2024. It is now read-only.

feat: video component #287

Merged
merged 27 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
e50e7c2
feat: add meeting kick user
afonsovinicius Jul 26, 2023
e95f793
fix: remote config path
afonsovinicius Jul 26, 2023
c20c491
fix: remove debugger
afonsovinicius Jul 26, 2023
a5c380e
fix: remove unused enum
afonsovinicius Jul 26, 2023
326930a
Merge pull request #275 from SuperViz/feat/add-meeting-kick-user
carlossantos74 Jul 27, 2023
b05d1d2
feat: send group and global config by param to components
carlossantos74 Aug 2, 2023
324e60c
feat: exports video component
carlossantos74 Aug 2, 2023
839335d
feat: initialize video component and add realtime observers
carlossantos74 Aug 2, 2023
6444483
refactor: remove config params and use config service from video-manager
carlossantos74 Aug 2, 2023
5fad3f4
feat: add subscribe to video realtime events
carlossantos74 Aug 3, 2023
3ff2e76
refactor: realtime events observers
carlossantos74 Aug 3, 2023
8a8fad4
feat: add support to subscribe and publish component events
carlossantos74 Aug 3, 2023
d35694b
feat: integrates participant events in to video component
carlossantos74 Aug 3, 2023
4d9afba
feat: integrates meeting events in to video component
carlossantos74 Aug 3, 2023
ab1535f
refactor: remove communicator service
carlossantos74 Aug 3, 2023
86ed859
chore(test-config): ignore entrypoint file in to coverage report
carlossantos74 Aug 3, 2023
53ca106
fix: change the transcript events to send message to video-frame
brunokunace Aug 4, 2023
439fd81
test: create test for setTranscript function in AblyRealtime
brunokunace Aug 4, 2023
8a72a8f
test: fix the transcript test param
brunokunace Aug 4, 2023
9332507
ci: lab version is lab
carlossantos74 Aug 4, 2023
c65331a
Merge branch 'beta' of github.com:SuperViz/sdk into fix/config-context
carlossantos74 Aug 6, 2023
2672d08
feat: add kick participant support
carlossantos74 Aug 6, 2023
b4304bf
Merge branch 'fix/transcript-events' of github.com:SuperViz/sdk into …
carlossantos74 Aug 6, 2023
e17b13d
feat: add transcript support
carlossantos74 Aug 6, 2023
6f9d94a
feat: unsubscribe from all observers when component is detached
carlossantos74 Aug 7, 2023
9c29371
feat: leave video when destroy is called
carlossantos74 Aug 7, 2023
e098d89
feat: exports video component by cdn
carlossantos74 Aug 7, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
run: yarn install
- name: Build package
run: |
touch .version.js && echo "echo \"export const version = 'beta'\" > .version.js" | bash -
touch .version.js && echo "echo \"export const version = 'lab'\" > .version.js" | bash -
yarn build
- name: Push
uses: s0/git-publish-subdir-action@develop
Expand Down
4 changes: 2 additions & 2 deletions __mocks__/plugins.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
import { DefaultIntegrationManagerOptions } from '../src/services/integration/types';

import { MOCK_AVATAR, MOCK_LOCAL_PARTICIPANT } from './participants.mock';
import { MOCK_REALTIME_SERVICE } from './realtime.mock';
import { ABLY_REALTIME_MOCK } from './realtime.mock';

export const MOCK_AVATAR_CONFIG: AvatarConfig = {
height: 1.8,
Expand Down Expand Up @@ -76,5 +76,5 @@ export const MOCK_INTEGRATION_MANAGER_OPTIONS: DefaultIntegrationManagerOptions
avatarConfig: MOCK_AVATAR_CONFIG,
participantList: MOCK_PARTICIPANT_TO_3D_LIST,
plugin: MOCK_PLUGIN,
RealtimeService: MOCK_REALTIME_SERVICE,
RealtimeService: ABLY_REALTIME_MOCK,
};
34 changes: 16 additions & 18 deletions __mocks__/realtime.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,17 @@ export const createRealtimeHistory = () => ({
'unit-test-message-3': new Array(10).fill(createRealtimeMessage('unit-test-message-3')),
});

export const MOCK_REALTIME_SERVICE: AblyRealtimeService = {
participantJoinedObserver: MOCK_OBSERVER_HELPER,
participantLeaveObserver: MOCK_OBSERVER_HELPER,
roomInfoUpdatedObserver: MOCK_OBSERVER_HELPER,
syncPropertiesObserver: MOCK_OBSERVER_HELPER,
participantsObserver: MOCK_OBSERVER_HELPER,
subscribeToParticipantUpdate: jest.fn(),
unsubscribeFromParticipantUpdate: jest.fn(),
updateMyProperties: jest.fn(),
subscribe: MOCK_OBSERVER_HELPER.subscribe,
unsubscribe: MOCK_OBSERVER_HELPER.unsubscribe,
getParticipantSlot: jest.fn(),
} as unknown as AblyRealtimeService;

export const ABLY_REALTIME_MOCK = {
export const ABLY_REALTIME_MOCK: AblyRealtimeService = {
isLocalParticipantHost: true,
setGather: jest.fn(),
setHost: jest.fn(),
setGridMode: jest.fn(),
setDrawing: jest.fn(),
freezeSync: jest.fn(),
setParticipantData: jest.fn(),
setSyncProperty: jest.fn(),
setKickParticipant: jest.fn(),
setTranscript: jest.fn(),
start: jest.fn(),
join: jest.fn(),
leave: jest.fn(),
Expand All @@ -48,8 +40,9 @@ export const ABLY_REALTIME_MOCK = {

return createRealtimeHistory();
}),
getSlotColor: jest.fn(() => {
return { color: MeetingColorsHex['#FFEF33'], name: MeetingColors.yellow };
getSlotColor: jest.fn().mockReturnValue({
color: MeetingColorsHex[0],
name: MeetingColors[0],
}),
roomInfoUpdatedObserver: MOCK_OBSERVER_HELPER,
participantsObserver: MOCK_OBSERVER_HELPER,
Expand All @@ -58,5 +51,10 @@ export const ABLY_REALTIME_MOCK = {
hostObserver: MOCK_OBSERVER_HELPER,
syncPropertiesObserver: MOCK_OBSERVER_HELPER,
kickAllParticipantsObserver: MOCK_OBSERVER_HELPER,
kickParticipantObserver: MOCK_OBSERVER_HELPER,
authenticationObserver: MOCK_OBSERVER_HELPER,
};
subscribeToParticipantUpdate: jest.fn(),
unsubscribeFromParticipantUpdate: jest.fn(),
updateMyProperties: jest.fn(),
getParticipantSlot: jest.fn(),
} as unknown as AblyRealtimeService;
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module.exports = {
'<rootDir>/src/**/*.ts',
'<rootDir>/src/**/*.js',
'!<rootDir>/src/web-components/**/*',
'!<rootDir>/src/index.ts',
],
coverageDirectory: '<rootDir>/coverage',
coverageReporters: ['html', 'lcov'].concat(argv.coverage ? ['text'] : []),
Expand Down
6 changes: 4 additions & 2 deletions src/common/types/cdn.types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { SuperVizSdk } from '../../types';
import { VideoComponent } from '../../components';
import { LauncherFacade } from '../../core/launcher/types';

import {
DeviceEvent,
Expand All @@ -12,12 +13,13 @@ import {
import { SuperVizSdkOptions } from './sdk-options.types';

export interface SuperVizCdn {
init: (apiKey: string, options: SuperVizSdkOptions) => Promise<SuperVizSdk>;
init: (apiKey: string, options: SuperVizSdkOptions) => Promise<LauncherFacade>;
MeetingEvent: typeof MeetingEvent;
RealtimeEvent: typeof RealtimeEvent;
DeviceEvent: typeof DeviceEvent;
MeetingState: typeof MeetingState;
MeetingConnectionStatus: typeof MeetingConnectionStatus;
MeetingControlsEvent: typeof MeetingControlsEvent;
ParticipantEvent: typeof ParticipantEvent;
VideoComponent: typeof VideoComponent;
}
10 changes: 6 additions & 4 deletions src/common/types/events.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export enum MeetingEvent {
MY_PARTICIPANT_UPDATED = 'my-participant.update',
MY_PARTICIPANT_LEFT = 'my-participant.left',
MY_PARTICIPANT_JOINED = 'my-participant.joined',
MEETING_KICK_PARTICIPANT = 'meeting.kick-participant',
DESTROY = 'destroy',
}

Expand All @@ -40,7 +41,6 @@ export enum MeetingControlsEvent {
}

export enum RealtimeEvent {
REALTIME_JOIN = 'realtime.join',
REALTIME_PARTICIPANT_LIST_UPDATE = 'realtime.participant-list-update',
REALTIME_HOST_CHANGE = 'realtime.host-change',
REALTIME_GRID_MODE_CHANGE = 'realtime.grid-mode-change',
Expand All @@ -51,11 +51,13 @@ export enum RealtimeEvent {
REALTIME_FOLLOW_PARTICIPANT = 'realtime.follow-participant',
REALTIME_SET_AVATAR = 'realtime.set-avatar',
REALTIME_DRAWING_CHANGE = 'realtime.drawing-change',
REALTIME_TRANSCRIPT_CHANGE = 'realtime.transcript-change',
}

export enum TranscriptionEvent {
TRANSCRIPTION_START = 'transcription.start',
TRANSCRIPTION_STOP = 'transcription.stop',
export enum TranscriptState {
TRANSCRIPT_START = 'transcript.start',
TRANSCRIPT_RUNNING = 'transcript.running',
TRANSCRIPT_STOP = 'transcript.stop',
}

export enum MeetingState {
Expand Down
85 changes: 79 additions & 6 deletions src/components/base/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { MOCK_LOCAL_PARTICIPANT } from '../../../__mocks__/participants.mock';
import { MOCK_REALTIME_SERVICE } from '../../../__mocks__/realtime.mock';
import { Participant } from '../../common/types/participant.types';
import { MOCK_CONFIG } from '../../../__mocks__/config.mock';
import { MOCK_OBSERVER_HELPER } from '../../../__mocks__/observer-helper.mock';
import { MOCK_GROUP, MOCK_LOCAL_PARTICIPANT } from '../../../__mocks__/participants.mock';
import { ABLY_REALTIME_MOCK } from '../../../__mocks__/realtime.mock';
import { Group, Participant } from '../../common/types/participant.types';
import { Logger } from '../../common/utils';
import { Configuration } from '../../services/config/types';
import { AblyRealtimeService } from '../../services/realtime';

import { BaseComponent } from '.';
Expand Down Expand Up @@ -45,11 +48,13 @@ describe('BaseComponent', () => {

DummyComponentInstance.attach({
localParticipant: MOCK_LOCAL_PARTICIPANT,
realtime: MOCK_REALTIME_SERVICE,
realtime: ABLY_REALTIME_MOCK,
group: MOCK_GROUP,
config: MOCK_CONFIG,
});

expect(DummyComponentInstance['localParticipant']).toEqual(MOCK_LOCAL_PARTICIPANT);
expect(DummyComponentInstance['realtime']).toEqual(MOCK_REALTIME_SERVICE);
expect(DummyComponentInstance['realtime']).toEqual(ABLY_REALTIME_MOCK);
expect(DummyComponentInstance['isAttached']).toBeTruthy();
expect(DummyComponentInstance['start']).toBeCalled();
});
Expand All @@ -61,6 +66,8 @@ describe('BaseComponent', () => {
DummyComponentInstance.attach({
localParticipant: null as unknown as Participant,
realtime: null as unknown as AblyRealtimeService,
group: null as unknown as Group,
config: null as unknown as Configuration,
});
}).toThrowError();
});
Expand All @@ -73,7 +80,9 @@ describe('BaseComponent', () => {

DummyComponentInstance.attach({
localParticipant: MOCK_LOCAL_PARTICIPANT,
realtime: MOCK_REALTIME_SERVICE,
realtime: ABLY_REALTIME_MOCK,
group: MOCK_GROUP,
config: MOCK_CONFIG,
});

DummyComponentInstance.detach();
Expand All @@ -84,6 +93,26 @@ describe('BaseComponent', () => {
expect(DummyComponentInstance['destroy']).toBeCalled();
});

test('should unsubscribe from all events', () => {
const callback = jest.fn();
DummyComponentInstance['destroy'] = jest.fn();

DummyComponentInstance.attach({
localParticipant: MOCK_LOCAL_PARTICIPANT,
realtime: ABLY_REALTIME_MOCK,
group: MOCK_GROUP,
config: MOCK_CONFIG,
});

DummyComponentInstance.subscribe('test', callback);

expect(DummyComponentInstance['observers']['test']).toBeDefined();

DummyComponentInstance.detach();

expect(DummyComponentInstance['observers']['test']).toBeUndefined();
});

test('should not detach the component if it is not attached', () => {
DummyComponentInstance['logger'].log = jest.fn();
expect(DummyComponentInstance.detach).toBeDefined();
Expand All @@ -93,4 +122,48 @@ describe('BaseComponent', () => {
expect(DummyComponentInstance['logger'].log).toBeCalled();
});
});

describe('subscribe', () => {
test('should subscribe to the event component with success', () => {
const callback = jest.fn();

expect(DummyComponentInstance.subscribe).toBeDefined();

DummyComponentInstance.subscribe('test', callback);

DummyComponentInstance['publish']('test', 'test');

expect(callback).toBeCalledWith('test');
});

test('should unsubscribe to the event component with success', () => {
const callback = jest.fn();

expect(DummyComponentInstance.subscribe).toBeDefined();

DummyComponentInstance.subscribe('test', callback);

DummyComponentInstance['publish']('test', 'test');

expect(callback).toBeCalledWith('test');

DummyComponentInstance.unsubscribe('test');

DummyComponentInstance['publish']('test', 'test');

expect(callback).toBeCalledTimes(1);
});

test('should skip unsubscribe if the event is not subscribed', () => {
expect(DummyComponentInstance.subscribe).toBeDefined();

DummyComponentInstance.unsubscribe('test');
});

test('should skip publish if the event is not subscribed', () => {
expect(DummyComponentInstance.subscribe).toBeDefined();

DummyComponentInstance['publish']('test', 'test');
});
});
});
76 changes: 68 additions & 8 deletions src/components/base/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { Participant } from '../../common/types/participant.types';
import { Logger } from '../../common/utils';
import { Group, Participant } from '../../common/types/participant.types';
import { Logger, Observer } from '../../common/utils';
import config from '../../services/config';
import { AblyRealtimeService } from '../../services/realtime';

import { DefaultAttachComponentOptions } from './types';

export abstract class BaseComponent {
private observers: Record<string, Observer> = {};

protected localParticipant: Participant;
protected group: Group;
protected realtime: AblyRealtimeService;
protected abstract name: string;
protected abstract logger: Logger;
Expand All @@ -17,18 +21,25 @@ export abstract class BaseComponent {
* @description attach component
* @returns {void}
*/
public attach = ({ realtime, localParticipant }: DefaultAttachComponentOptions): void => {
if (!realtime || !localParticipant) {
const message = `${this.name} @ attach - realtime and localParticipant are required`;
public attach = (params: DefaultAttachComponentOptions): void => {
if (Object.values(params).includes(null) || Object.values(params).includes(undefined)) {
const message = `${this.name} @ attach - params are required`;

this.logger.log(message);
throw new Error(message);
}

this.logger.log('attached');
const { realtime, localParticipant, group, config: globalConfig } = params;

config.setConfig(globalConfig);

this.realtime = realtime;
this.localParticipant = localParticipant;
this.group = group;
this.isAttached = true;

this.logger.log('attached');

this.start();
};

Expand All @@ -43,12 +54,61 @@ export abstract class BaseComponent {
return;
}

this.logger.log('detached');
this.destroy();

this.realtime = undefined;
this.localParticipant = undefined;
this.isAttached = false;

this.logger.log('detached');
this.destroy();
Object.keys(this.observers).forEach((type) => this.unsubscribe(type));
};

/**
* @function subscribe
* @description Subscribe to an event
* @param type - event type
* @param listener - event callback
* @returns {void}
*/
public subscribe = (type: string, listener: Function): void => {
this.logger.log(`subscribed to ${type} event`);

if (!this.observers[type]) {
this.observers[type] = new Observer({ logger: this.logger });
}

this.observers[type].subscribe(listener);
};

/**
* @function unsubscribe
* @description Unsubscribe from an event
* @param type - event type
* @returns {void}
*/
public unsubscribe = (type: string): void => {
this.logger.log(`unsubscribed from ${type} event`);

if (!this.observers[type]) return;

this.observers[type].reset();
delete this.observers[type];
};

/**
* @function publish
* @description Publish an event to client
* @param type - event type
* @param data - event data
* @returns {void}
*/
protected publish = (type: string, data?: unknown): void => {
const hasListenerRegistered = type in this.observers;

if (!hasListenerRegistered) return;

this.observers[type].publish(data);
};

protected abstract destroy(): void;
Expand Down
6 changes: 4 additions & 2 deletions src/components/base/types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Participant } from '../../common/types/participant.types';
import { Group, Participant } from '../../common/types/participant.types';
import { Configuration } from '../../services/config/types';
import { AblyRealtimeService } from '../../services/realtime';
import { AblyRealtime } from '../../services/realtime/ably/types';

export interface DefaultAttachComponentOptions {
realtime: AblyRealtimeService;
localParticipant: Participant;
group: Group;
config: Configuration;
}
Loading
Loading