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

feat: realtime component presence #739

Merged
merged 9 commits into from
Aug 12, 2024
3 changes: 3 additions & 0 deletions src/components/realtime/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Logger, Observable, Observer } from '../../common/utils';
import { IOC } from '../../services/io';

import { RealtimeChannelEvent, RealtimeChannelState, RealtimeData, RealtimeMessage } from './types';
import { RealtimePresence } from './presence';

export class Channel extends Observable {
private name: string;
Expand All @@ -19,6 +20,7 @@ export class Channel extends Observable {
event: string;
callback: (data: unknown) => void;
}> = [];
public participant: RealtimePresence;

constructor(
name: string,
Expand All @@ -36,6 +38,7 @@ export class Channel extends Observable {

this.subscribeToRealtimeEvents();
this.logger.log('started');
this.participant = new RealtimePresence(this.channel);
}

public async disconnect(): Promise<void> {
Expand Down
4 changes: 4 additions & 0 deletions src/components/realtime/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { RealtimeComponentState } from './types';

import { Realtime } from '.';
import { LIMITS_MOCK } from '../../../__mocks__/limits.mock';
import { StoreType } from '../../common/types/stores.types';

jest.mock('lodash/throttle', () => jest.fn((fn) => fn));
jest.useFakeTimers();
Expand All @@ -22,6 +23,9 @@ describe('realtime component', () => {
console.error = jest.fn();
console.debug = jest.fn();

const { hasJoinedRoom } = useStore(StoreType.GLOBAL);
hasJoinedRoom.publish(true);

RealtimeComponentInstance = new Realtime();
RealtimeComponentInstance.attach({
ioc: new IOC(MOCK_LOCAL_PARTICIPANT),
Expand Down
15 changes: 15 additions & 0 deletions src/components/realtime/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Participant } from '../../common/types/participant.types';
import { StoreType } from '../../common/types/stores.types';
import { Logger } from '../../common/utils';
import { useGlobalStore } from '../../services/stores';
import { BaseComponent } from '../base';
import { ComponentNames } from '../types';

import { Channel } from './channel';

import {
RealtimeChannelEvent,
RealtimeChannelState,
Expand Down Expand Up @@ -42,6 +44,19 @@ export class Realtime extends BaseComponent {
* @returns {Channel}
*/
public connect(name: string): Promise<Channel> {
if (!this.channel) {
return new Promise<Channel>((resolve) => {
const { localParticipant } = useGlobalStore();

localParticipant.subscribe('connect-after-init', (participant) => {
if (!participant.activeComponents.includes(ComponentNames.REALTIME)) return;

localParticipant.unsubscribe('connect-after-init');
resolve(this.connect(name));
});
});
}

let channel: Channel = this.channels.get(name);
if (channel) return channel as unknown as Promise<Channel>;

Expand Down
59 changes: 59 additions & 0 deletions src/components/realtime/presence.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { PresenceEvents, Room } from '../../lib/socket';

import { RealtimePresence } from './presence';
import { MOCK_IO } from '../../../__mocks__/io.mock';

describe('realtime component', () => {
let RealtimePresenceInstance: RealtimePresence;

beforeEach(() => {
jest.clearAllMocks();

const room = new MOCK_IO.Realtime('', '', '');
RealtimePresenceInstance = new RealtimePresence(room.connect() as unknown as Room);
});

afterEach(() => {
jest.clearAllMocks();
});

describe('Realtime Participant Presence', () => {
test('should update presence', () => {
const spy = jest.spyOn(RealtimePresenceInstance['room'].presence as any, 'update' as any);
const data = {
id: '123',
name: 'John Doe',
};

RealtimePresenceInstance['update'](data);

expect(spy).toHaveBeenCalledWith(data);
});

test('should subscribe to presence events', () => {
const spy = jest.spyOn(RealtimePresenceInstance['room'].presence as any, 'on' as any);
const event = MOCK_IO.PresenceEvents.UPDATE;
const callback = jest.fn();

RealtimePresenceInstance['subscribe'](event as PresenceEvents, callback);

expect(spy).toHaveBeenCalledWith(event, callback);
});

test('should unsubscribe from presence events', () => {
const spy = jest.spyOn(RealtimePresenceInstance['room'].presence as any, 'off' as any);
const event = MOCK_IO.PresenceEvents.UPDATE;

RealtimePresenceInstance['unsubscribe'](event as PresenceEvents);

expect(spy).toHaveBeenCalledWith(event);
});

test('should get all presences', () => {
const spy = jest.spyOn(RealtimePresenceInstance['room'].presence as any, 'get' as any);
RealtimePresenceInstance['getAll']();

expect(spy).toHaveBeenCalled();
});
});
});
41 changes: 41 additions & 0 deletions src/components/realtime/presence.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Logger } from '../../common/utils';
import * as Socket from '../../lib/socket';

export class RealtimePresence {
private logger: Logger;

constructor(private room: Socket.Room) {
this.logger = new Logger('@superviz/sdk/realtime-presence');
}

public update(data: any) {
this.logger.log('Realtime Presence @ update presence', data);
this.room.presence.update(data);
}
carlossantos74 marked this conversation as resolved.
Show resolved Hide resolved

public subscribe<T>(event: Socket.PresenceEvents, callback: Socket.PresenceCallback<T>) {
this.logger.log('Realtime Presence @ subscribe', event);
this.room.presence.on(event, callback);
}

public unsubscribe(event: Socket.PresenceEvents) {
this.logger.log('Realtime Presence @ unsubscribe', event);
this.room.presence.off(event);
}
carlossantos74 marked this conversation as resolved.
Show resolved Hide resolved

public getAll() {
this.logger.log('Realtime Presence @ get all');
let presences: Socket.PresenceEvent[];
this.room.presence.get(
(data) => {
presences = data;
},
(error) => {
const message = `${error.name} - ${error.message}`;
this.logger.log(error);
console.error(message);
},
);
return presences;
}
}
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import {
} from './services/video-conference-manager/types';

export { StoreType } from './common/types/stores.types';

export { PresenceEvents } from './lib/socket/common/types/event.types';
export { Presence3DManager } from './services/presence-3d-manager';

export { FieldEvents } from './components/form-elements/types';
Expand Down
8 changes: 5 additions & 3 deletions src/lib/socket/presence/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class PresenceRoom {
constructor(private io: Socket, private presence: Presence, private roomId: string) {
this.logger = new Logger('@superviz/sdk/socket-client/presence');

this.registerSubsjects();
this.registerSubjects();
this.subscribeToPresenceEvents();
}

Expand Down Expand Up @@ -90,11 +90,11 @@ export class PresenceRoom {
}

/**
* @function registerSubsjects
* @function registerSubjects
* @description Register the subjects for the presence events
* @returns {void}
*/
private registerSubsjects(): void {
private registerSubjects(): void {
this.observers.set(PresenceEvents.JOINED_ROOM, new Subject());
this.observers.set(PresenceEvents.LEAVE, new Subject());
this.observers.set(PresenceEvents.UPDATE, new Subject());
Expand Down Expand Up @@ -127,6 +127,8 @@ export class PresenceRoom {
*/
public off(event: PresenceEvents): void {
this.observers.get(event).unsubscribe();
this.observers.delete(event);
this.observers.set(event, new Subject());
}

/**
Expand Down
Loading