From f5142ba93e0988cdad42acf609e9faee2a80ef02 Mon Sep 17 00:00:00 2001 From: Robert Long Date: Fri, 15 Oct 2021 16:41:23 -0700 Subject: [PATCH] Add new GroupCallInspector --- package.json | 1 + src/GroupCallInspector.jsx | 143 +++++++++++++++++++++++++++++++++++++ src/Room.jsx | 16 +++++ yarn.lock | 125 +++++++++++++++++++++++++++++++- 4 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 src/GroupCallInspector.jsx diff --git a/package.json b/package.json index 63bbf0f..b760eb5 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "re-resizable": "^6.9.0", "react": "^17.0.0", "react-dom": "^17.0.0", + "react-json-view": "^1.21.3", "react-router-dom": "^5.2.0" }, "devDependencies": { diff --git a/src/GroupCallInspector.jsx b/src/GroupCallInspector.jsx new file mode 100644 index 0000000..cf35aad --- /dev/null +++ b/src/GroupCallInspector.jsx @@ -0,0 +1,143 @@ +import React, { useEffect, useState, useMemo } from "react"; +import { useCallback } from "react"; +import ReactJson from "react-json-view"; + +function getCallUserId(call) { + return call.getOpponentMember()?.userId || call.invitee || null; +} + +function getCallState(call) { + return { + opponentMemberId: getCallUserId(call), + state: call.state, + direction: call.direction, + }; +} + +function getHangupCallState(call) { + return { + ...getCallState(call), + hangupReason: call.hangupReason, + }; +} + +export function GroupCallInspector({ client, groupCall, show }) { + const [roomStateEvents, setRoomStateEvents] = useState([]); + const [toDeviceEvents, setToDeviceEvents] = useState([]); + const [state, setState] = useState({ + userId: client.getUserId(), + }); + + const updateState = useCallback( + (next) => setState((prev) => ({ ...prev, ...next })), + [] + ); + + useEffect(() => { + function onUpdateRoomState(event) { + if (event) { + setRoomStateEvents((prev) => [ + ...prev, + { + eventType: event.getType(), + stateKey: event.getStateKey(), + content: event.getContent(), + }, + ]); + } + + const roomEvent = groupCall.room.currentState + .getStateEvents("org.matrix.msc3401.call", groupCall.groupCallId) + .getContent(); + + const memberEvents = Object.fromEntries( + groupCall.room.currentState + .getStateEvents("org.matrix.msc3401.call.member") + .map((event) => [event.getStateKey(), event.getContent()]) + ); + + updateState({ + ["org.matrix.msc3401.call"]: roomEvent, + ["org.matrix.msc3401.call.member"]: memberEvents, + }); + } + + function onCallsChanged() { + const calls = groupCall.calls.map(getCallState); + + updateState({ calls }); + } + + function onCallHangup(call) { + setState(({ hangupCalls, ...rest }) => ({ + ...rest, + hangupCalls: hangupCalls + ? [...hangupCalls, getHangupCallState(call)] + : [getHangupCallState(call)], + })); + } + + function onToDeviceEvent(event) { + const eventType = event.getType(); + + if ( + !( + eventType.startsWith("m.call.") || + eventType.startsWith("org.matrix.call.") + ) + ) { + return; + } + + const content = event.getContent(); + + if (content.conf_id && content.conf_id !== groupCall.groupCallId) { + return; + } + + setToDeviceEvents((prev) => [...prev, { eventType, content }]); + } + + client.on("RoomState.events", onUpdateRoomState); + groupCall.on("calls_changed", onCallsChanged); + client.on("state", onCallsChanged); + client.on("hangup", onCallHangup); + client.on("toDeviceEvent", onToDeviceEvent); + + onUpdateRoomState(); + }, [client, groupCall]); + + const toDeviceEventsByCall = useMemo(() => { + const result = {}; + + for (const event of toDeviceEvents) { + const callId = event.content.call_id; + result[callId] = result[callId] || []; + result[callId].push(event); + } + + return result; + }, [toDeviceEvents]); + + return ( +
+ {show && ( + + )} +
+ ); +} diff --git a/src/Room.jsx b/src/Room.jsx index dc66389..f75a96f 100644 --- a/src/Room.jsx +++ b/src/Room.jsx @@ -24,6 +24,7 @@ import { LayoutToggleButton, ScreenshareButton, DropdownButton, + SettingsButton, } from "./RoomButton"; import { Header, LeftNav, RightNav, CenterNav } from "./Header"; import { Button } from "./Input"; @@ -37,6 +38,7 @@ import { useCallFeed } from "matrix-react-sdk/src/hooks/useCallFeed"; import { useMediaStream } from "matrix-react-sdk/src/hooks/useMediaStream"; import { fetchGroupCall } from "./ConferenceCallManagerHooks"; import { ErrorModal } from "./ErrorModal"; +import { GroupCallInspector } from "./GroupCallInspector"; function useLoadGroupCall(client, roomId) { const [state, setState] = useState({ @@ -109,6 +111,7 @@ export function GroupCallView({ client, groupCall }) { } else if (state === GroupCallState.Entered) { return ( {roomName} + setShowInspector((prev) => !prev)} + /> + ); } diff --git a/yarn.lock b/yarn.lock index 2c30067..2da842e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -169,7 +169,7 @@ resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.15.7.tgz" integrity sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g== -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a" integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw== @@ -625,6 +625,11 @@ base-x@^3.0.2: dependencies: safe-buffer "^5.0.1" +base16@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base16/-/base16-1.0.0.tgz#e297f60d7ec1014a7a971a39ebc8a98c0b681e70" + integrity sha1-4pf2DX7BAUp6lxo568ipjAtoHnA= + base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" @@ -917,6 +922,13 @@ crc-32@^0.3.0: resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-0.3.0.tgz#6a3d3687f5baec41f7e9b99fe1953a2e5d19775e" integrity sha1-aj02h/W67EH36bmf4ZU6Ll0Zd14= +cross-fetch@^3.0.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39" + integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ== + dependencies: + node-fetch "2.6.1" + css-blank-pseudo@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5" @@ -1307,6 +1319,18 @@ fbemitter@^2.0.0: dependencies: fbjs "^0.8.4" +fbemitter@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/fbemitter/-/fbemitter-3.0.0.tgz#00b2a1af5411254aab416cd75f9e6289bee4bff3" + integrity sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw== + dependencies: + fbjs "^3.0.0" + +fbjs-css-vars@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8" + integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== + fbjs@0.1.0-alpha.7: version "0.1.0-alpha.7" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.1.0-alpha.7.tgz#ad4308b8f232fb3c73603349ea725d1e9c39323c" @@ -1329,6 +1353,19 @@ fbjs@^0.8.4: setimmediate "^1.0.5" ua-parser-js "^0.7.18" +fbjs@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.0.tgz#0907067fb3f57a78f45d95f1eacffcacd623c165" + integrity sha512-dJd4PiDOFuhe7vk4F80Mba83Vr2QuK86FoxtgPmzBqEJahncp+13YCmfoa53KHCo6OnlXLG7eeMWPfB5CrpVKg== + dependencies: + cross-fetch "^3.0.4" + fbjs-css-vars "^1.0.0" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.18" + fflate@^0.4.1: version "0.4.8" resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae" @@ -1372,6 +1409,14 @@ flux@2.1.1: fbjs "0.1.0-alpha.7" immutable "^3.7.4" +flux@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/flux/-/flux-4.0.2.tgz#d71dcaf6cb51ca059f303f3d964d6f325d444952" + integrity sha512-u/ucO5ezm3nBvdaSGkWpDlzCePoV+a9x3KHmy13TV/5MzOaCZDN8Mfd94jmf0nOi8ZZay+nOKbBUkOe2VNaupQ== + dependencies: + fbemitter "^3.0.0" + fbjs "^3.0.0" + focus-lock@^0.9.1: version "0.9.2" resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.9.2.tgz#9d30918aaa99b1b97677731053d017f82a540d5b" @@ -1749,6 +1794,16 @@ lodash-move@^1.1.1: dependencies: lodash "^4.6.1" +lodash.curry@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170" + integrity sha1-JI42By7ekGUB11lmIAqG2riyMXA= + +lodash.flow@^3.3.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a" + integrity sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o= + lodash@^4.17.20, lodash@^4.6.1: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" @@ -1905,6 +1960,11 @@ nanoid@^3.1.25: resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.1.28.tgz" integrity sha512-gSu9VZ2HtmoKYe/lmyPFES5nknFrHa+/DT9muUFWFMi6Jh9E1I7bkvlQ8xxf1Kos9pi9o8lBnIOkatMhKX/YUw== +node-fetch@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + node-fetch@^1.0.1: version "1.7.3" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" @@ -2442,6 +2502,11 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +pure-color@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/pure-color/-/pure-color-1.3.0.tgz#1fe064fb0ac851f0de61320a8bf796836422f33e" + integrity sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4= + qrcode@^1.4.4: version "1.4.4" resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.4.4.tgz#f0c43568a7e7510a55efc3b88d9602f71963ea83" @@ -2484,6 +2549,16 @@ re-resizable@^6.9.0: dependencies: fast-memoize "^2.5.1" +react-base16-styling@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/react-base16-styling/-/react-base16-styling-0.6.0.tgz#ef2156d66cf4139695c8a167886cb69ea660792c" + integrity sha1-7yFW1mz0E5aVyKFniGy2nqZgeSw= + dependencies: + base16 "^1.0.0" + lodash.curry "^4.0.1" + lodash.flow "^3.3.0" + pure-color "^1.2.0" + react-beautiful-dnd@^13.1.0: version "13.1.0" resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-13.1.0.tgz#ec97c81093593526454b0de69852ae433783844d" @@ -2535,6 +2610,21 @@ react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-json-view@^1.21.3: + version "1.21.3" + resolved "https://registry.yarnpkg.com/react-json-view/-/react-json-view-1.21.3.tgz#f184209ee8f1bf374fb0c41b0813cff54549c475" + integrity sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw== + dependencies: + flux "^4.0.1" + react-base16-styling "^0.6.0" + react-lifecycles-compat "^3.0.4" + react-textarea-autosize "^8.3.2" + +react-lifecycles-compat@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + react-redux@^7.2.0: version "7.2.5" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.5.tgz#213c1b05aa1187d9c940ddfc0b29450957f6a3b8" @@ -2576,6 +2666,15 @@ react-router@5.2.1: tiny-invariant "^1.0.2" tiny-warning "^1.0.0" +react-textarea-autosize@^8.3.2: + version "8.3.3" + resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.3.3.tgz#f70913945369da453fd554c168f6baacd1fa04d8" + integrity sha512-2XlHXK2TDxS6vbQaoPbMOfQ8GK7+irc2fVK6QFIcC8GOnH3zI/v481n+j1L0WaPVvKxwesnY93fEfH++sus2rQ== + dependencies: + "@babel/runtime" "^7.10.2" + use-composed-ref "^1.0.0" + use-latest "^1.0.0" + react-transition-group@^4.4.1: version "4.4.2" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470" @@ -2871,6 +2970,11 @@ tough-cookie@~2.5.0: psl "^1.1.28" punycode "^2.1.1" +ts-essentials@^2.0.3: + version "2.0.12" + resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-2.0.12.tgz#c9303f3d74f75fa7528c3d49b80e089ab09d8745" + integrity sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w== + tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -2928,6 +3032,25 @@ use-callback-ref@^1.2.5: resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.2.5.tgz#6115ed242cfbaed5915499c0a9842ca2912f38a5" integrity sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg== +use-composed-ref@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.1.0.tgz#9220e4e94a97b7b02d7d27eaeab0b37034438bbc" + integrity sha512-my1lNHGWsSDAhhVAT4MKs6IjBUtG6ZG11uUqexPH9PptiIZDQOzaF4f5tEbJ2+7qvNbtXNBbU3SfmN+fXlWDhg== + dependencies: + ts-essentials "^2.0.3" + +use-isomorphic-layout-effect@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz#7bb6589170cd2987a152042f9084f9effb75c225" + integrity sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ== + +use-latest@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/use-latest/-/use-latest-1.2.0.tgz#a44f6572b8288e0972ec411bdd0840ada366f232" + integrity sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw== + dependencies: + use-isomorphic-layout-effect "^1.0.0" + use-memo-one@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.2.tgz#0c8203a329f76e040047a35a1197defe342fab20"