diff --git a/src/equicordplugins/orbolayBridge/index.tsx b/src/equicordplugins/orbolayBridge/index.tsx index e4165fa7..59519f59 100644 --- a/src/equicordplugins/orbolayBridge/index.tsx +++ b/src/equicordplugins/orbolayBridge/index.tsx @@ -80,13 +80,13 @@ const settings = definePluginSettings({ let ws: WebSocket | null = null; let currentChannel = null; -const waitForPopulate = async fn => { +async function waitForPopulate(fn) { while (true) { const result = await fn(); if (result) return result; await new Promise(r => setTimeout(r, 500)); } -}; +} function stateToPayload(guildId: string, state: ChannelState) { const user = UserStore.getUser(state.userId); @@ -128,11 +128,10 @@ const incoming = payload => { }); break; case "STOP_STREAM": { - const userId = UserStore.getCurrentUser()?.id; + const userId = UserStore.getCurrentUser().id; const voiceState = VoiceStateStore.getVoiceStateForUser(userId); const channel = ChannelStore.getChannel(voiceState.channelId); - // If any of these are null, we can't do anything if (!userId || !voiceState || !channel) return; FluxDispatcher.dispatch({ @@ -144,93 +143,12 @@ const incoming = payload => { } }; -const handleSpeaking = dispatch => { - ws?.send( - JSON.stringify({ - cmd: "VOICE_STATE_UPDATE", - state: { - userId: dispatch.userId, - speaking: dispatch.speakingFlags === 1, - }, - }) - ); -}; - -const handleMessageNotification = dispatch => { - ws?.send( - JSON.stringify({ - cmd: "MESSAGE_NOTIFICATION", - message: { - title: dispatch.title, - body: dispatch.body, - icon: dispatch.icon, - channelId: dispatch.channelId, - } - }) - ); -}; - -const handleVoiceStateUpdates = async dispatch => { - // Ensure we are in the channel that the update is for - const { id } = UserStore.getCurrentUser(); - - for (const state of dispatch.voiceStates) { - const ourState = state.userId === id; - const { guildId } = state; - - if (ourState) { - if (state.channelId && state.channelId !== currentChannel) { - const voiceStates = await waitForPopulate(() => - VoiceStateStore?.getVoiceStatesForChannel(state.channelId) - ); - - ws?.send( - JSON.stringify({ - cmd: "CHANNEL_JOINED", - states: Object.values(voiceStates).map(s => stateToPayload(guildId, s as ChannelState)), - }) - ); - - currentChannel = state.channelId; - - break; - } else if (!state.channelId) { - ws?.send( - JSON.stringify({ - cmd: "CHANNEL_LEFT", - }) - ); - - currentChannel = null; - - break; - } - } - - // If this is for the channel we are in, send a VOICE_STATE_UPDATE - if ( - !!currentChannel && - (state.channelId === currentChannel || - state.oldChannelId === currentChannel) - ) { - ws?.send( - JSON.stringify({ - cmd: "VOICE_STATE_UPDATE", - state: stateToPayload(guildId, state as ChannelState), - }) - ); - } - } -}; - const createWebsocket = () => { console.log("Attempting to connect to Orbolay server"); - // First ensure old connection is closed if (ws?.close) ws.close(); setTimeout(() => { - // If the ws is not ready, kill it and log if (ws?.readyState !== WebSocket.OPEN) { Toasts.show({ message: "Orbolay websocket could not connect. Is it running?", @@ -261,24 +179,20 @@ const createWebsocket = () => { id: Toasts.genId(), }); - // Send over the config const config = { ...settings.store, userId: null, }; - // Ensure we track the current user id config.userId = await waitForPopulate(() => UserStore.getCurrentUser().id); ws?.send(JSON.stringify({ cmd: "REGISTER_CONFIG", ...config })); - // Send initial channel joined (if the user is in a channel) const userVoiceState = VoiceStateStore.getVoiceStateForUser(config.userId); - - if (!userVoiceState) return; - + const guildId = ChannelStore.getChannel(userVoiceState.channelId).guild_id; const channelState = VoiceStateStore.getVoiceStatesForChannel(userVoiceState.channelId); - const { guildId } = userVoiceState; + + if (!guildId || !channelState) return; ws?.send( JSON.stringify({ @@ -292,23 +206,79 @@ const createWebsocket = () => { }; export default definePlugin({ - name: "Orbolay Bridge", + name: "OrbolayBridge", description: "Bridge plugin to connect Orbolay to Discord", authors: [EquicordDevs.SpikeHD], settings, + flux: { + SPEAKING({ userId, speakingFlags }) { + ws?.send( + JSON.stringify({ + cmd: "VOICE_STATE_UPDATE", + state: { + userId: userId, + speaking: speakingFlags === 1, + }, + }) + ); + }, + async VOICE_STATE_UPDATES({ voiceStates }) { + const { id } = UserStore.getCurrentUser(); + + for (const state of voiceStates) { + const ourState = state.userId === id; + const { guildId } = state; + + if (ourState) { + if (state.channelId && state.channelId !== currentChannel) { + const voiceStates = await waitForPopulate(() => VoiceStateStore.getVoiceStatesForChannel(state.channelId)); + + ws?.send( + JSON.stringify({ + cmd: "CHANNEL_JOINED", + states: Object.values(voiceStates).map(s => stateToPayload(guildId, s as ChannelState)), + }) + ); + + currentChannel = state.channelId; + break; + } else if (!state.channelId) { + ws?.send( + JSON.stringify({ + cmd: "CHANNEL_LEFT", + }) + ); + + currentChannel = null; + break; + } + } + + if (!!currentChannel && (state.channelId === currentChannel || state.oldChannelId === currentChannel)) { + ws?.send( + JSON.stringify({ + cmd: "VOICE_STATE_UPDATE", + state: stateToPayload(guildId, state as ChannelState), + }) + ); + } + } + }, + RPC_NOTIFICATION_CREATE({ title, body, icon, channelId }) { + ws?.send( + JSON.stringify({ + cmd: "MESSAGE_NOTIFICATION", + message: { + title: title, + body: body, + icon: icon, + channelId: channelId, + } + }) + ); + } + }, start() { createWebsocket(); - - FluxDispatcher.subscribe("SPEAKING", handleSpeaking); - FluxDispatcher.subscribe("VOICE_STATE_UPDATES", handleVoiceStateUpdates); - FluxDispatcher.subscribe("RPC_NOTIFICATION_CREATE", handleMessageNotification); - }, - stop() { - ws?.close(); - ws = null; - - FluxDispatcher.unsubscribe("SPEAKING", handleSpeaking); - FluxDispatcher.unsubscribe("VOICE_STATE_UPDATES", handleVoiceStateUpdates); - FluxDispatcher.unsubscribe("RPC_NOTIFICATION_CREATE", handleMessageNotification); } });