Group events by calls or users
This commit is contained in:
parent
87660e8873
commit
661e3dd98e
6 changed files with 211 additions and 162 deletions
11
package-lock.json
generated
11
package-lock.json
generated
|
|
@ -7,6 +7,7 @@
|
||||||
"": {
|
"": {
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"classnames": "^2.3.1",
|
||||||
"color-hash": "^2.0.1",
|
"color-hash": "^2.0.1",
|
||||||
"events": "^3.3.0",
|
"events": "^3.3.0",
|
||||||
"matrix-js-sdk": "^12.0.1",
|
"matrix-js-sdk": "^12.0.1",
|
||||||
|
|
@ -588,6 +589,11 @@
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/classnames": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
|
||||||
|
},
|
||||||
"node_modules/color-convert": {
|
"node_modules/color-convert": {
|
||||||
"version": "1.9.3",
|
"version": "1.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||||
|
|
@ -2039,6 +2045,11 @@
|
||||||
"supports-color": "^5.3.0"
|
"supports-color": "^5.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"classnames": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
|
||||||
|
},
|
||||||
"color-convert": {
|
"color-convert": {
|
||||||
"version": "1.9.3",
|
"version": "1.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
"serve": "vite preview"
|
"serve": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"classnames": "^2.3.1",
|
||||||
"color-hash": "^2.0.1",
|
"color-hash": "^2.0.1",
|
||||||
"events": "^3.3.0",
|
"events": "^3.3.0",
|
||||||
"matrix-js-sdk": "^12.0.1",
|
"matrix-js-sdk": "^12.0.1",
|
||||||
|
|
|
||||||
|
|
@ -134,9 +134,10 @@ export class ConferenceCallManager extends EventEmitter {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.joined = false;
|
this.joined = false;
|
||||||
this.room = null;
|
this.room = null;
|
||||||
|
const localUserId = client.getUserId();
|
||||||
this.localParticipant = {
|
this.localParticipant = {
|
||||||
local: true,
|
local: true,
|
||||||
userId: client.getUserId(),
|
userId: localUserId,
|
||||||
feed: null,
|
feed: null,
|
||||||
call: null,
|
call: null,
|
||||||
muted: true,
|
muted: true,
|
||||||
|
|
@ -144,20 +145,24 @@ export class ConferenceCallManager extends EventEmitter {
|
||||||
this.participants = [this.localParticipant];
|
this.participants = [this.localParticipant];
|
||||||
this.pendingCalls = [];
|
this.pendingCalls = [];
|
||||||
this.callUserMap = new Map();
|
this.callUserMap = new Map();
|
||||||
this.debugState = new Map();
|
this.debugState = {
|
||||||
this._setDebugState(client.getUserId(), "you");
|
users: new Map(),
|
||||||
|
calls: new Map(),
|
||||||
|
};
|
||||||
this.client.on("event", this._onEvent);
|
this.client.on("event", this._onEvent);
|
||||||
this.client.on("RoomState.members", this._onMemberChanged);
|
this.client.on("RoomState.members", this._onMemberChanged);
|
||||||
this.client.on("Call.incoming", this._onIncomingCall);
|
this.client.on("Call.incoming", this._onIncomingCall);
|
||||||
}
|
}
|
||||||
|
|
||||||
join(roomId) {
|
setRoom(roomId) {
|
||||||
this.joined = true;
|
|
||||||
|
|
||||||
this._addDebugEvent(this.client.getUserId(), "joined call");
|
|
||||||
|
|
||||||
this.roomId = roomId;
|
this.roomId = roomId;
|
||||||
this.room = this.client.getRoom(this.roomId);
|
this.room = this.client.getRoom(this.roomId);
|
||||||
|
}
|
||||||
|
|
||||||
|
join() {
|
||||||
|
this.joined = true;
|
||||||
|
|
||||||
|
this._setDebugState(this.client.getUserId(), null, "you");
|
||||||
|
|
||||||
const activeConf = this.room.currentState
|
const activeConf = this.room.currentState
|
||||||
.getStateEvents(CONF_ROOM, "")
|
.getStateEvents(CONF_ROOM, "")
|
||||||
|
|
@ -169,18 +174,12 @@ export class ConferenceCallManager extends EventEmitter {
|
||||||
|
|
||||||
const roomMemberIds = this.room.getMembers().map(({ userId }) => userId);
|
const roomMemberIds = this.room.getMembers().map(({ userId }) => userId);
|
||||||
|
|
||||||
for (const userId of this.debugState.keys()) {
|
|
||||||
if (roomMemberIds.indexOf(userId) === -1) {
|
|
||||||
this.debugState.delete(userId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
roomMemberIds.forEach((userId) => {
|
roomMemberIds.forEach((userId) => {
|
||||||
this._processMember(userId);
|
this._processMember(userId);
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const { call, onHangup, onReplaced } of this.pendingCalls) {
|
for (const { call, onHangup, onReplaced } of this.pendingCalls) {
|
||||||
if (call.roomId !== roomId) {
|
if (call.roomId !== this.roomId) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -200,31 +199,66 @@ export class ConferenceCallManager extends EventEmitter {
|
||||||
const roomId = event.getRoomId();
|
const roomId = event.getRoomId();
|
||||||
const type = event.getType();
|
const type = event.getType();
|
||||||
|
|
||||||
if (type.startsWith("m.call.") || type.startsWith("me.robertlong.conf")) {
|
if (roomId === this.roomId && type.startsWith("m.call.")) {
|
||||||
const content = event.getContent();
|
const sender = event.getSender();
|
||||||
const details = { content: event.toJSON(), roomId };
|
const { call_id } = event.getContent();
|
||||||
|
|
||||||
if (content.invitee && content.call_id) {
|
if (call_id) {
|
||||||
this.callUserMap.set(content.call_id, content.invitee);
|
if (this.debugState.calls.has(call_id)) {
|
||||||
details.to = content.invitee;
|
const callState = this.debugState.calls.get(call_id);
|
||||||
} else if (content.call_id) {
|
callState.events.push(event);
|
||||||
details.to = this.callUserMap.get(content.call_id);
|
} else {
|
||||||
|
this.debugState.calls.set(call_id, {
|
||||||
|
state: "unknown",
|
||||||
|
events: [event],
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type) {
|
if (this.debugState.users.has(sender)) {
|
||||||
case "m.call.invite":
|
const userState = this.debugState.users.get(sender);
|
||||||
case "m.call.candidates":
|
userState.events.push(event);
|
||||||
case "m.call.answer":
|
} else {
|
||||||
case "m.call.hangup":
|
this.debugState.users.set(sender, {
|
||||||
case "m.call.select_answer":
|
state: "unknown",
|
||||||
details.callId = content.call_id;
|
events: [event],
|
||||||
break;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this._addDebugEvent(event.getSender(), type, details);
|
this.emit("debug");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_setDebugState(userId, callId, state) {
|
||||||
|
if (userId) {
|
||||||
|
const userState = this.debugState.users.get(userId);
|
||||||
|
|
||||||
|
if (userState) {
|
||||||
|
userState.state = state;
|
||||||
|
} else {
|
||||||
|
this.debugState.users.set(userId, {
|
||||||
|
state,
|
||||||
|
events: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callId) {
|
||||||
|
const callState = this.debugState.calls.get(callId);
|
||||||
|
|
||||||
|
if (callState) {
|
||||||
|
callState.state = state;
|
||||||
|
} else {
|
||||||
|
this.debugState.calls.set(callId, {
|
||||||
|
state,
|
||||||
|
events: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emit("debug");
|
||||||
|
}
|
||||||
|
|
||||||
_updateParticipantState = () => {
|
_updateParticipantState = () => {
|
||||||
const userId = this.client.getUserId();
|
const userId = this.client.getUserId();
|
||||||
const currentMemberState = this.room.currentState.getStateEvents(
|
const currentMemberState = this.room.currentState.getStateEvents(
|
||||||
|
|
@ -286,20 +320,19 @@ export class ConferenceCallManager extends EventEmitter {
|
||||||
new Date().getTime() - participantTimeout > PARTICIPANT_TIMEOUT
|
new Date().getTime() - participantTimeout > PARTICIPANT_TIMEOUT
|
||||||
) {
|
) {
|
||||||
// Member is inactive so don't call them.
|
// Member is inactive so don't call them.
|
||||||
this._setDebugState(userId, "inactive");
|
this._setDebugState(userId, null, "inactive");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only initiate a call with a user who has a userId that is lexicographically
|
// Only initiate a call with a user who has a userId that is lexicographically
|
||||||
// less than your own. Otherwise, that user will call you.
|
// less than your own. Otherwise, that user will call you.
|
||||||
if (userId < localUserId) {
|
if (userId < localUserId) {
|
||||||
this._setDebugState(userId, "waiting for invite");
|
this._setDebugState(userId, null, "waiting for invite");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const call = this.client.createCall(this.roomId, userId);
|
const call = this.client.createCall(this.roomId, userId);
|
||||||
this._addCall(call, userId);
|
this._addCall(call, userId);
|
||||||
this._setDebugState(userId, "calling");
|
|
||||||
call.placeVideoCall();
|
call.placeVideoCall();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -342,7 +375,6 @@ export class ConferenceCallManager extends EventEmitter {
|
||||||
|
|
||||||
const userId = call.opponentMember.userId;
|
const userId = call.opponentMember.userId;
|
||||||
this._addCall(call, userId);
|
this._addCall(call, userId);
|
||||||
this._setDebugState(userId, "answered");
|
|
||||||
call.answer();
|
call.answer();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -365,8 +397,9 @@ export class ConferenceCallManager extends EventEmitter {
|
||||||
call,
|
call,
|
||||||
});
|
});
|
||||||
|
|
||||||
this._setDebugCallId(userId, call.callId);
|
call.on("state", (state) =>
|
||||||
|
this._setDebugState(userId, call.callId, state)
|
||||||
|
);
|
||||||
call.on("feeds_changed", () => this._onCallFeedsChanged(call));
|
call.on("feeds_changed", () => this._onCallFeedsChanged(call));
|
||||||
call.on("hangup", () => this._onCallHangup(call));
|
call.on("hangup", () => this._onCallHangup(call));
|
||||||
|
|
||||||
|
|
@ -388,7 +421,6 @@ export class ConferenceCallManager extends EventEmitter {
|
||||||
|
|
||||||
if (!this.localParticipant.feed && localFeeds.length > 0) {
|
if (!this.localParticipant.feed && localFeeds.length > 0) {
|
||||||
this.localParticipant.call = call;
|
this.localParticipant.call = call;
|
||||||
this._setDebugCallId(this.localParticipant.userId, call.callId);
|
|
||||||
this.localParticipant.feed = localFeeds[0];
|
this.localParticipant.feed = localFeeds[0];
|
||||||
participantsChanged = true;
|
participantsChanged = true;
|
||||||
}
|
}
|
||||||
|
|
@ -400,7 +432,6 @@ export class ConferenceCallManager extends EventEmitter {
|
||||||
|
|
||||||
if (remoteFeeds.length > 0 && remoteParticipant.feed !== remoteFeeds[0]) {
|
if (remoteFeeds.length > 0 && remoteParticipant.feed !== remoteFeeds[0]) {
|
||||||
remoteParticipant.feed = remoteFeeds[0];
|
remoteParticipant.feed = remoteFeeds[0];
|
||||||
this._setDebugState(call.opponentMember.userId, "streaming");
|
|
||||||
participantsChanged = true;
|
participantsChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -410,16 +441,14 @@ export class ConferenceCallManager extends EventEmitter {
|
||||||
};
|
};
|
||||||
|
|
||||||
_onCallHangup = (call) => {
|
_onCallHangup = (call) => {
|
||||||
if (call.hangupReason === "replaced") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._setDebugState(call.opponentMember.userId, "hungup");
|
|
||||||
|
|
||||||
const participantIndex = this.participants.findIndex(
|
const participantIndex = this.participants.findIndex(
|
||||||
(p) => !p.local && p.call === call
|
(p) => !p.local && p.call === call
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (call.hangupReason === "replaced") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (participantIndex === -1) {
|
if (participantIndex === -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -436,16 +465,13 @@ export class ConferenceCallManager extends EventEmitter {
|
||||||
|
|
||||||
if (localFeeds.length > 0) {
|
if (localFeeds.length > 0) {
|
||||||
this.localParticipant.call = call;
|
this.localParticipant.call = call;
|
||||||
this._setDebugCallId(this.localParticipant.userId, call.callId);
|
|
||||||
this.localParticipant.feed = localFeeds[0];
|
this.localParticipant.feed = localFeeds[0];
|
||||||
} else {
|
} else {
|
||||||
this.localParticipant.call = null;
|
this.localParticipant.call = null;
|
||||||
this._setDebugCallId(this.localParticipant.userId, null);
|
|
||||||
this.localParticipant.feed = null;
|
this.localParticipant.feed = null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.localParticipant.call = null;
|
this.localParticipant.call = null;
|
||||||
this._setDebugCallId(this.localParticipant.userId, null);
|
|
||||||
this.localParticipant.feed = null;
|
this.localParticipant.feed = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -454,17 +480,11 @@ export class ConferenceCallManager extends EventEmitter {
|
||||||
};
|
};
|
||||||
|
|
||||||
_onCallReplaced = (call, newCall) => {
|
_onCallReplaced = (call, newCall) => {
|
||||||
this._addDebugEvent(call.opponentMember.userId, "replaced", {
|
|
||||||
callId: call.callId,
|
|
||||||
newCallId: newCall.callId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const remoteParticipant = this.participants.find(
|
const remoteParticipant = this.participants.find(
|
||||||
(p) => !p.local && p.call === call
|
(p) => !p.local && p.call === call
|
||||||
);
|
);
|
||||||
|
|
||||||
remoteParticipant.call = newCall;
|
remoteParticipant.call = newCall;
|
||||||
this._setDebugCallId(remoteParticipant.userId, newCall.callId);
|
|
||||||
|
|
||||||
newCall.on("feeds_changed", () => this._onCallFeedsChanged(newCall));
|
newCall.on("feeds_changed", () => this._onCallFeedsChanged(newCall));
|
||||||
newCall.on("hangup", () => this._onCallHangup(newCall));
|
newCall.on("hangup", () => this._onCallHangup(newCall));
|
||||||
|
|
@ -507,48 +527,10 @@ export class ConferenceCallManager extends EventEmitter {
|
||||||
this.participants = [this.localParticipant];
|
this.participants = [this.localParticipant];
|
||||||
this.localParticipant.feed = null;
|
this.localParticipant.feed = null;
|
||||||
this.localParticipant.call = null;
|
this.localParticipant.call = null;
|
||||||
this._setDebugCallId(this.localParticipant.userId, null);
|
|
||||||
|
|
||||||
this.emit("participants_changed");
|
this.emit("participants_changed");
|
||||||
}
|
}
|
||||||
|
|
||||||
_addDebugEvent(sender, type, content) {
|
|
||||||
if (!this.debugState.has(sender)) {
|
|
||||||
this.debugState.set(sender, {
|
|
||||||
callId: null,
|
|
||||||
state: "unknown",
|
|
||||||
events: [{ type, ...content }],
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const { events } = this.debugState.get(sender);
|
|
||||||
events.push({ type, roomId: this.roomId, ...content });
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emit("debug");
|
|
||||||
}
|
|
||||||
|
|
||||||
_setDebugState(userId, state) {
|
|
||||||
if (!this.debugState.has(userId)) {
|
|
||||||
this.debugState.set(userId, { state, callId: null, events: [] });
|
|
||||||
} else {
|
|
||||||
const userState = this.debugState.get(userId);
|
|
||||||
userState.state = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emit("debug");
|
|
||||||
}
|
|
||||||
|
|
||||||
_setDebugCallId(userId, callId) {
|
|
||||||
if (!this.debugState.has(userId)) {
|
|
||||||
this.debugState.set(userId, { state: "unknown", callId, events: [] });
|
|
||||||
} else {
|
|
||||||
const userState = this.debugState.get(userId);
|
|
||||||
userState.callId = callId;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emit("debug");
|
|
||||||
}
|
|
||||||
|
|
||||||
logout() {
|
logout() {
|
||||||
localStorage.removeItem("matrix-auth-store");
|
localStorage.removeItem("matrix-auth-store");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,8 @@ export function useVideoRoom(manager, roomId, timeout = 5000) {
|
||||||
error: undefined,
|
error: undefined,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
manager.setRoom(roomId);
|
||||||
|
|
||||||
manager.client.joinRoom(roomId).catch((err) => {
|
manager.client.joinRoom(roomId).catch((err) => {
|
||||||
setState((prevState) => ({ ...prevState, loading: false, error: err }));
|
setState((prevState) => ({ ...prevState, loading: false, error: err }));
|
||||||
});
|
});
|
||||||
|
|
@ -196,7 +198,7 @@ export function useVideoRoom(manager, roomId, timeout = 5000) {
|
||||||
|
|
||||||
manager.on("participants_changed", onParticipantsChanged);
|
manager.on("participants_changed", onParticipantsChanged);
|
||||||
|
|
||||||
manager.join(roomId);
|
manager.join();
|
||||||
|
|
||||||
setState((prevState) => ({
|
setState((prevState) => ({
|
||||||
...prevState,
|
...prevState,
|
||||||
|
|
|
||||||
163
src/DevTools.jsx
163
src/DevTools.jsx
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import ColorHash from "color-hash";
|
import ColorHash from "color-hash";
|
||||||
|
import classNames from "classnames";
|
||||||
import styles from "./DevTools.module.css";
|
import styles from "./DevTools.module.css";
|
||||||
|
|
||||||
const colorHash = new ColorHash({ lightness: 0.8 });
|
const colorHash = new ColorHash({ lightness: 0.8 });
|
||||||
|
|
@ -25,13 +26,27 @@ function CallId({ callId, ...rest }) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sortEntries(a, b) {
|
||||||
|
const aInactive = a[1].state === "inactive";
|
||||||
|
const bInactive = b[1].state === "inactive";
|
||||||
|
|
||||||
|
if (aInactive && !bInactive) {
|
||||||
|
return 1;
|
||||||
|
} else if (bInactive && !aInactive) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return a[0] < b[0] ? -1 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function DevTools({ manager }) {
|
export function DevTools({ manager }) {
|
||||||
const [debugState, setDebugState] = useState(manager.debugState);
|
const [debugState, setDebugState] = useState(manager.debugState);
|
||||||
const [selectedEvent, setSelectedEvent] = useState();
|
const [selectedEvent, setSelectedEvent] = useState();
|
||||||
|
const [activeTab, setActiveTab] = useState("users");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function onRoomDebug() {
|
function onRoomDebug() {
|
||||||
setDebugState(manager.debugState);
|
setDebugState({ ...manager.debugState });
|
||||||
}
|
}
|
||||||
|
|
||||||
manager.on("debug", onRoomDebug);
|
manager.on("debug", onRoomDebug);
|
||||||
|
|
@ -47,15 +62,50 @@ export function DevTools({ manager }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.devTools}>
|
<div className={styles.devTools}>
|
||||||
{Array.from(debugState.entries()).map(([userId, props]) => (
|
<div className={styles.toolbar}>
|
||||||
<UserState
|
<div
|
||||||
key={userId}
|
className={classNames(styles.tab, {
|
||||||
roomId={manager.roomId}
|
[styles.activeTab]: activeTab === "users",
|
||||||
onSelectEvent={setSelectedEvent}
|
})}
|
||||||
userId={userId}
|
onClick={() => setActiveTab("users")}
|
||||||
{...props}
|
>
|
||||||
/>
|
Users
|
||||||
))}
|
</div>
|
||||||
|
<div
|
||||||
|
className={classNames(styles.tab, {
|
||||||
|
[styles.activeTab]: activeTab === "calls",
|
||||||
|
})}
|
||||||
|
onClick={() => setActiveTab("calls")}
|
||||||
|
>
|
||||||
|
Calls
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={styles.devToolsContainer}>
|
||||||
|
{activeTab === "users" &&
|
||||||
|
Array.from(debugState.users.entries())
|
||||||
|
.sort(sortEntries)
|
||||||
|
.map(([userId, props]) => (
|
||||||
|
<EventContainer
|
||||||
|
key={userId}
|
||||||
|
showCallId
|
||||||
|
title={<UserId userId={userId} />}
|
||||||
|
{...props}
|
||||||
|
onSelect={setSelectedEvent}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{activeTab === "calls" &&
|
||||||
|
Array.from(debugState.calls.entries())
|
||||||
|
.sort(sortEntries)
|
||||||
|
.map(([callId, props]) => (
|
||||||
|
<EventContainer
|
||||||
|
key={callId}
|
||||||
|
showSender
|
||||||
|
title={<CallId callId={callId} />}
|
||||||
|
{...props}
|
||||||
|
onSelect={setSelectedEvent}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
{selectedEvent && (
|
{selectedEvent && (
|
||||||
<EventViewer
|
<EventViewer
|
||||||
event={selectedEvent}
|
event={selectedEvent}
|
||||||
|
|
@ -66,7 +116,7 @@ export function DevTools({ manager }) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function UserState({ roomId, userId, state, callId, events, onSelectEvent }) {
|
function EventContainer({ title, state, events, ...rest }) {
|
||||||
const eventsRef = useRef();
|
const eventsRef = useRef();
|
||||||
const [autoScroll, setAutoScroll] = useState(true);
|
const [autoScroll, setAutoScroll] = useState(true);
|
||||||
|
|
||||||
|
|
@ -90,78 +140,59 @@ function UserState({ roomId, userId, state, callId, events, onSelectEvent }) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.user}>
|
<div className={styles.user}>
|
||||||
<div className={styles.userId}>
|
<div className={styles.userId}>
|
||||||
<UserId userId={userId} />
|
<span>{title}</span>
|
||||||
<span>{`(${state})`}</span>
|
<span>{`(${state})`}</span>
|
||||||
{callId && <CallId callId={callId} />}
|
|
||||||
</div>
|
</div>
|
||||||
<div ref={eventsRef} className={styles.events} onScroll={onScroll}>
|
<div ref={eventsRef} className={styles.events} onScroll={onScroll}>
|
||||||
{events
|
{events.map((event, idx) => (
|
||||||
.filter((e) => e.roomId === roomId)
|
<EventItem key={idx} event={event} {...rest} />
|
||||||
.map((event, idx) => (
|
))}
|
||||||
<div
|
|
||||||
className={styles.event}
|
|
||||||
key={idx}
|
|
||||||
onClick={() => onSelectEvent(event)}
|
|
||||||
>
|
|
||||||
<span className={styles.eventType}>{event.type}</span>
|
|
||||||
{event.callId && (
|
|
||||||
<CallId className={styles.eventDetails} callId={event.callId} />
|
|
||||||
)}
|
|
||||||
{event.newCallId && (
|
|
||||||
<>
|
|
||||||
<span className={styles.eventDetails}>{"->"}</span>
|
|
||||||
<CallId
|
|
||||||
className={styles.eventDetails}
|
|
||||||
callId={event.newCallId}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{event.to && (
|
|
||||||
<UserId className={styles.eventDetails} userId={event.to} />
|
|
||||||
)}
|
|
||||||
{event.reason && (
|
|
||||||
<span className={styles.eventDetails}>{event.reason}</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function EventItem({ event, showCallId, showSender, onSelect }) {
|
||||||
|
const type = event.getType();
|
||||||
|
const sender = event.getSender();
|
||||||
|
const { call_id, invitee } = event.getContent();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.event} onClick={() => onSelect(event)}>
|
||||||
|
{showSender && sender && (
|
||||||
|
<UserId className={styles.eventDetails} userId={sender} />
|
||||||
|
)}
|
||||||
|
<span className={styles.eventType}>{type}</span>
|
||||||
|
{showCallId && call_id && (
|
||||||
|
<CallId className={styles.eventDetails} callId={call_id} />
|
||||||
|
)}
|
||||||
|
{invitee && <UserId className={styles.eventDetails} userId={invitee} />}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function EventViewer({ event, onClose }) {
|
function EventViewer({ event, onClose }) {
|
||||||
|
const type = event.getType();
|
||||||
|
const sender = event.getSender();
|
||||||
|
const { call_id, invitee } = event.getContent();
|
||||||
|
const json = event.toJSON();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.eventViewer}>
|
<div className={styles.eventViewer}>
|
||||||
<p>Event Type: {event.type}</p>
|
<p>Event Type: {type}</p>
|
||||||
{event.callId && (
|
<p>Sender: {sender}</p>
|
||||||
|
{call_id && (
|
||||||
<p>
|
<p>
|
||||||
Call Id: <CallId callId={event.callId} />
|
Call Id: <CallId callId={call_id} />
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{event.newCallId && (
|
{invitee && (
|
||||||
<p>
|
<p>
|
||||||
New Call Id:
|
Invitee: <UserId userId={invitee} />
|
||||||
<CallId callId={event.newCallId} />
|
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{event.to && (
|
<p>Raw Event:</p>
|
||||||
<p>
|
<pre className={styles.content}>{JSON.stringify(json, undefined, 2)}</pre>
|
||||||
To: <UserId userId={event.to} />
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
{event.reason && (
|
|
||||||
<p>
|
|
||||||
Reason: <span>{event.reason}</span>
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
{event.content && (
|
|
||||||
<>
|
|
||||||
<p>Content:</p>
|
|
||||||
<pre className={styles.content}>
|
|
||||||
{JSON.stringify(event.content, undefined, 2)}
|
|
||||||
</pre>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<button onClick={onClose}>Close</button>
|
<button onClick={onClose}>Close</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,31 @@
|
||||||
.devTools {
|
.devTools {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 250px;
|
flex-direction: column;
|
||||||
border-top: 2px solid #111;
|
border-top: 2px solid #111;
|
||||||
gap: 2px;
|
|
||||||
background-color: #111;
|
background-color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
display: flex;
|
||||||
|
background-color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
vertical-align: middle;
|
||||||
|
padding: 4px 8px;
|
||||||
|
background-color: #444;
|
||||||
|
margin: 0 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activeTab {
|
||||||
|
background-color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.devToolsContainer {
|
||||||
|
display: flex;
|
||||||
|
height: 250px;
|
||||||
|
gap: 2px;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue