Skip to content

Commit

Permalink
Merge pull request #188 from whereby/thomas/PAN-694-refactor-rtc-anal…
Browse files Browse the repository at this point in the history
…ytics-events

Refactor rtc custom events map
  • Loading branch information
thyal authored Jan 12, 2024
2 parents 940601e + f214b80 commit 57ab3a6
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 29 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@whereby.com/browser-sdk",
"version": "2.0.0-beta3",
"version": "2.0.0-beta4",
"description": "Modules for integration Whereby video in web apps",
"author": "Whereby AS",
"license": "MIT",
Expand Down
74 changes: 46 additions & 28 deletions src/lib/core/redux/slices/rtcAnalytics.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,46 @@
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import { ActionCreatorWithPayload, PayloadAction, createSlice, isAnyOf } from "@reduxjs/toolkit";
import { AsyncThunkFulfilledActionCreator } from "@reduxjs/toolkit/dist/createAsyncThunk";
import { RootState } from "../store";
import { createAppThunk } from "../thunk";
import { ThunkConfig, createAppThunk } from "../thunk";
import { createReactor, startAppListening } from "../listenerMiddleware";
import { selectRtcConnectionRaw, selectRtcManagerInitialized, selectRtcStatus } from "./rtcConnection";
import { selectAppDisplayName, selectAppExternalId } from "./app";
import { selectOrganizationId } from "./organization";
import { selectLocalParticipantRole, selectSelfId } from "./localParticipant";
import {
doEnableAudio,
doEnableVideo,
doSetDisplayName,
selectLocalParticipantRole,
selectSelfId,
} from "./localParticipant";
import { selectSignalStatus } from "./signalConnection";
import { selectDeviceId } from "./deviceCredentials";
import { selectIsCameraEnabled, selectIsMicrophoneEnabled, selectLocalMediaStream } from "./localMedia";
import { selectLocalScreenshareStream } from "./localScreenshare";
import { doSetDevice, selectIsCameraEnabled, selectIsMicrophoneEnabled, selectLocalMediaStream } from "./localMedia";
import { doStartScreenshare, selectLocalScreenshareStream, stopScreenshare } from "./localScreenshare";

type RtcAnalyticsCustomEvent = {
actionType: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
action: ActionCreatorWithPayload<any> | AsyncThunkFulfilledActionCreator<any, any, ThunkConfig> | null;
rtcEventName: string;
getValue: (state: RootState) => unknown;
getOutput: (value: unknown) => unknown;
};

export const rtcAnalyticsCustomEvents: { [key: string]: RtcAnalyticsCustomEvent } = {
audioEnabled: {
actionType: "localParticipant/doEnableAudio/fulfilled",
action: doEnableAudio.fulfilled,
rtcEventName: "audioEnabled",
getValue: (state: RootState) => selectIsMicrophoneEnabled(state),
getOutput: (value) => ({ enabled: value }),
},
videoEnabled: {
actionType: "localParticipant/doEnableVideo/fulfilled",
action: doEnableVideo.fulfilled,
rtcEventName: "videoEnabled",
getValue: (state: RootState) => selectIsCameraEnabled(state),
getOutput: (value) => ({ enabled: value }),
},
localStream: {
actionType: "localMedia/reactSetDevice/fulfilled",
action: doSetDevice.fulfilled,
rtcEventName: "localStream",
getValue: (state: RootState) =>
selectLocalMediaStream(state)
Expand All @@ -41,7 +49,7 @@ export const rtcAnalyticsCustomEvents: { [key: string]: RtcAnalyticsCustomEvent
getOutput: (value) => ({ stream: value }),
},
localScreenshareStream: {
actionType: "localScreenshare/doStartScreenshare/fulfilled",
action: doStartScreenshare.fulfilled,
rtcEventName: "localScreenshareStream",
getValue: (state: RootState) =>
selectLocalScreenshareStream(state)
Expand All @@ -50,61 +58,71 @@ export const rtcAnalyticsCustomEvents: { [key: string]: RtcAnalyticsCustomEvent
getOutput: (value) => ({ tracks: value }),
},
localScreenshareStreamStopped: {
actionType: "localScreeenshare/stopScreenshare",
action: stopScreenshare,
rtcEventName: "localScreenshareStream",
getValue: () => () => null,
getOutput: () => ({}),
},
displayName: {
actionType: "localParticipant/doSetDisplayName/fulfilled",
action: doSetDisplayName.fulfilled,
rtcEventName: "displayName",
getValue: (state: RootState) => selectAppDisplayName(state),
getOutput: (value) => ({ displayName: value }),
},
clientId: {
actionType: "",
action: null,
rtcEventName: "clientId",
getValue: (state: RootState) => selectSelfId(state),
getOutput: (value) => ({ clientId: value }),
},
deviceId: {
actionType: "",
action: null,
rtcEventName: "deviceId",
getValue: (state: RootState) => selectDeviceId(state),
getOutput: (value) => ({ deviceId: value }),
},
externalId: {
actionType: "",
action: null,
rtcEventName: "externalId",
getValue: (state: RootState) => selectAppExternalId(state),
getOutput: (value) => ({ externalId: value }),
},
organizationId: {
actionType: "",
action: null,
rtcEventName: "organizationId",
getValue: (state: RootState) => selectOrganizationId(state),
getOutput: (value) => ({ organizationId: value }),
},
signalConnectionStatus: {
actionType: "",
action: null,
rtcEventName: "signalConnectionStatus",
getValue: (state: RootState) => selectSignalStatus(state),
getOutput: (value) => ({ status: value }),
},
rtcConnectionStatus: {
actionType: "",
action: null,
rtcEventName: "rtcConnectionStatus",
getValue: (state: RootState) => selectRtcStatus(state),
getOutput: (value) => ({ status: value }),
},
userRole: {
actionType: "",
action: null,
rtcEventName: "userRole",
getValue: (state: RootState) => selectLocalParticipantRole(state),
getOutput: (value) => ({ userRole: value }),
},
};

const rtcCustomEventActions = Object.values(rtcAnalyticsCustomEvents)
.map(({ action }) => action)
.filter(
(
action
): action is
| ActionCreatorWithPayload<unknown, string>
| AsyncThunkFulfilledActionCreator<unknown, unknown, ThunkConfig> => action !== null
);

const makeComparable = (value: unknown) => {
if (typeof value === "object") return JSON.stringify(value);

Expand All @@ -128,7 +146,13 @@ export const rtcAnalyticsSlice = createSlice({
name: "rtcAnalytics",
reducers: {
updateReportedValues(state, action: PayloadAction<{ rtcEventName: string; value: unknown }>) {
state.reportedValues[action.payload.rtcEventName] = action.payload.value;
return {
...state,
reportedValues: {
...state.reportedValues,
[action.payload.rtcEventName]: action.payload.value,
},
};
},
},
});
Expand Down Expand Up @@ -158,20 +182,14 @@ export const doRtcAnalyticsCustomEventsInitialize = createAppThunk(() => (dispat
export const { updateReportedValues } = rtcAnalyticsSlice.actions;

startAppListening({
predicate: (_action) => {
const rtcCustomEventActions = Object.values(rtcAnalyticsCustomEvents).map(({ actionType }) => actionType);

const isRtcEvent = rtcCustomEventActions.includes(_action.type);

return isRtcEvent;
},
matcher: isAnyOf(...rtcCustomEventActions),
effect: ({ type }, { getState, dispatch }) => {
const state: RootState = getState();

const rtcManager = selectRtcConnectionRaw(state).rtcManager;
if (!rtcManager) return;

const rtcCustomEvent = Object.values(rtcAnalyticsCustomEvents).find(({ actionType }) => actionType === type);
const rtcCustomEvent = Object.values(rtcAnalyticsCustomEvents).find(({ action }) => action?.type === type);
if (!rtcCustomEvent) return;

const { getValue, getOutput, rtcEventName } = rtcCustomEvent;
Expand Down

0 comments on commit 57ab3a6

Please sign in to comment.